В новой версии (2.3.0-preview1) руби что-то пошло не так. Разработчики MRI поддержали фичу сравнения хэшей по отношению включения при помощи операторов сравнения. Никого не смутило, что это частично упорядоченное множество. Ок, сравнения классов в языке уже живут очень давно. Но для них хотя бы есть специальный результат сравнения несравнимых
(
Read more... )
Comments 7
Почему должно было? Это же отношение порядка.
Оно с чистым сердцем говорит {a: 1} <= {b: 2} -- false и {b: 2} <= {a: 1} -- тоже false. Программистская и общечеловеческая интуиция говорит, что a < b - это отрицание a >=b.
Математика с тобой не согласна. Выполнение либо a≤b либо b≤a требуется только для отношения линейного порядка, но совершенно не обязано для частичного.
Я не знаю о чему думает человек который пытается отсортировать частично упорядоченное множество результат же неоднозначен. Особенно если они делают это функцией, преднозначенной для полностью упорядоченных множеств. Это типичный случай undefined behaviour.
Если раньше был эксепшен, такое решение, конечно, нарушает обратную совместимость. Это не слишком хорошо, но случается.
Reply
Вот ты часто встречал такие конструкции?
if a == b
elsif a < b
elsif b < a ( ... )
Reply
там явно указано, что для соритровок и многих других подобных алгоритмов (бинарный поиск, например) требуется strict weak ordering.
Мало того, в стандартной библиотеке есть stable_sort, который кроме прочего дает однозначный результат, даже если объекты которые, вроде как, равны не совпадают.
Как ты думаешь для кого подобные вещи пишутся?;)
В смысле слабого порядка всё логично: все несравнимые хеши необходимо считать равными:). Это пофиксит и проблемы с твоим примером и с сортировками. Т.е. само по себе введение таких сравнений не страшно.
Другое дело, что существующее определение == не совпадает с соотношением эквивалентности задаваемым <=, что полностью рушит подобную картину. И это уже гораздо более серьёзная проблема ( ... )
Reply
Кстати, я проглядел этот эпик фейл в реализации:
{a: 1, b: 2} <= {a: 1, b: 3}
{a: 1, b: 3} <= {a: 1, b: 2}
Реализация, которая сломала ключевой юзкейс фичи - использование в тестировании. Правда пугает.
А что ты имеешь ввиду, когда говоришь про согласованность <= и ==?
К вопросу про некорректность. Разве a<=b не эквивалентно a < b || a == b? Или это всего лишь !(b < a) ?
Раньше в руби всё делалось оператором <=>, который возвращал положительное, отрицательное или нулевое значение, а остальные операторы опирались на него. ( ... )
Reply
В C++ (на котором я, в основном, пишу и потому с ним сравниваю), такое бы считалось идеолгоически неправильным, т.к. считается что операторы сравнения задают слабый порядок, а функции базовой библиотеки (типа sort) НЕ ДОЛЖНЫ выбрасывать исключение, если оно не пришло из метода объекта, который им подсунули. Штука в том, что исключение это дорого. Именно в такие моменты я понимаю, что c++ это все таки очень низкоуровневый язык.
Reply
Оператор == определен вообще у всего. По умолчанию сравнивает object_id, то есть проверяет, что две ссылки указывают на один объект. В подклассах, понятно, переопределен.
Метод <=> определен на всех объектах (ну почти на всех, кроме самого нижнего уровня иерархии, ниже Object). Возвращает он -1,0,1 или nil. В Object он определен так: a<=>b = 0, если a==b, иначе nil. Был миксин Comparable, который при включении в класс давал методы <,<=,==,>,>=,between?, основываясь на результатах метода <=>.
Сравнение хэшей на данный момент реализовано так (то как написано в багтрекере не соответствует действительности): оператор == остался прежним, это строгое равенство пар ключ-значение (не учитывающее порядок добавления ключей в хэш). Оператор <=> НЕ переопределен и имеет ту же реализацию, что у класса Object: возвращает 0 либо nil. Зато появились не привязанные ( ... )
Reply
Leave a comment