Комментарии 21
Я создал для Rust крейт
num-ord
, позволяющий корректно сравнивать два любых встроенных числовых типа.
Вот так вот люди стараются, наводят строгости, чтобы помочь программистам устранить путаницу в типах и проистекающие из этого ошибки разной степени катастрофичности, а потом приходит эдакий мистер Секонд: "Го сравнивать всё со всем, я создал!"
(рекомендация врача: комментарий следует принимать с немножечком несерьёзности)
Статья так то про частный случай интеграции интерфейсов
Но что если мы хотим строгого неравенства? Теперь наш трюк с floor/ceil добавляет проблемы, связанные с равенством. Решить их можно отдельной проверкой на равенство в области определения целых чисел, а затем проверкой на неравенство в области определения чисел с плавающей запятой
Ага, сразу видно кто не читал Кнута :-)
Можно же воспользоваться тем, что x < f эквивалентно x < ceil(f), а x > f эквивалентно x > floor(f)
Downloads all time: 193
Интересно, но за год не так много людей захотело посравнивать числа таким образом. И зависимостью, по крайней мере на crates.io, тоже никто не стал делать.
Ой. C++ автоматически преобразовал -1 в unsigned int, из-за чего значение превратилось в максимальное значение типа (которое очевидно больше 1). Но, по крайней мере, современный компилятор по умолчанию ведь предупреждает о таких вещах? [...] Ну, по крайней мере, он не выполняет втихомолку ошибочную компиляцию…Type promotion полностью определен в стандарте, что не делает его менее популярным способом стрельбы по ногам.
в дополнение еще на уроках информатики в советской школе рассказывали, что вещественные числа нельзя сравнивать напрямую оператором равенства. Как минимум должна использоваться конструкция если (a-b)<epsilon то тогда значения считаются условно равными. Эпсилон задавался уже под конкретную задачу.
На любом языке, где есть перегрузка соответствующих операторов. А на плюсах наверняка можно получить и около нулевой оверхед.
На счёт fixed point не уверен, но в том же C# из коробки есть decimal, с которым удобно с десятичными дробями работать с достаточно высокой для денег точностью.
А Delphi прекрасно справился со сравнением Signed и Unsigned переменных.
writeln((-1) <= Cardinal(1)); //TRUE
И вывел предупреждение
W1022 Comparison always evaluates to True
и
W1023 Comparing signed and unsigned types - widened both operands
предлагаемое решение ужасно. Нет никаких причин для паники. Наиболее эффективное решение здесь — преобразовать оба значения
Конечно, глупо спорить с переводом, тем не менее автор оригинальной статьи слишком категоричен в своих суждениях. Если бы существовало одно единственное лучшее решение — оно бы и было реализовано в большинстве ЯП, вытеснив все остальные. На практике мы видим, что это не так.
Rust умышленно следует парадигме т.н. сильной типизации, при которой неявное конвертирование типов запрещено. В этом есть своя логика — ведь далеко не все операции со значениями разных типов имеют смысл. Например, нельзя сравнивать количество часов и количество километров, или прибавлять одно к другому (а вот делить — можно).
Rust идёт дальше и вводит понятие единиц измерения (measurements), позволяя добавить ограничения даже на значения одного и того же типа. Что уж говорить про разные типы: когда в программе встречается сравнение знакового и беззнакового целого — это с большой вероятностью ошибка программиста. Если же это делается умышленно, то это должно быть отражено в коде через явное приведение типов.
Rust идёт дальше и вводит понятие единиц измерения (measurements)
Мне кажется, вы либо имеете в виду newtype, которые всё-таки являются прозрачной обёрткой, а не "ограничениями для одного и того же типа", либо имеете в виду F#, у которого такая фича и правда есть (и даже делить километры на часы можно)
> "Компилятор должен сам делать всё правильно, а не заставлять людей выполнять вручную преобразования, которые могут быть и ошибочными, или, хуже того, втихомолку генерировать неверный код."
Например, компилятор Delphi делает это настолько педантично, что иногда приходится сильно поприседать, чтобы исключить генерацию в коде этих специальных преобразований, когда заранее известно, что коллизий при несовпадении типов не будет. Приходится аккуратно и точно использовать типы данных, чтобы код не содержал лишнего.
Что может быть проще (сложнее), чем упорядочивание чисел?