Здравствуйте, igna, Вы писали:
I>Менее абстрактная задача:
I>Определить класс SpaceInsensitiveString, при сравнении двух объектов которого метод equals...
I>Задача опять же непротиворечива, но отсутствие мультиметодов делает ее решение невозможным.
Это не задача, это решение. Причем не очень удачное в том плане, что требует изменения классов эквивалентности строк. Тут дело даже не в ООП, а в желании нарушить эквивалентность.
Все равно что "хочу написать объект, который будет равен всему, и до фени что перестанет работать половина FCL".
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Все равно что "хочу написать объект, который будет равен всему, и до фени что перестанет работать половина FCL".
I>Ну зачем передергивать-то, какому всему?
А где грань между тем что бы сломать эквивалентность только строк или вообще Object-ам?
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>А где грань между тем что бы сломать эквивалентность только строк или вообще Object-ам?
I>Используя твою терминологию, String.equals "ломает эквивалентность Object-ам".
Это не так. Ни при каких обстоятельствах String.Equals(object) не вернет true, если object не является экземпляром класса String. Точно так же Object.Equals(object) не вернет true если object является экземпляром класса String.
А вот неверным образом перекрытый Object.Equals(object) может вернуть true для строки. Но этот случай не попадает под "String.equals ломает эквивалентность".
Здравствуйте, samius, Вы писали:
S>Ни при каких обстоятельствах String.Equals(object) не вернет true, если object не является экземпляром класса String.
Это ограничение надуманно и вызвано исключительно неполноценностью классического ООП без мультиметодов.
Здравствуйте, igna, Вы писали:
I>Менее абстрактная задача: I>Определить класс SpaceInsensitiveString, при сравнении двух объектов которого метод equals считает две любые последовательности пробелов равными. Дополнительно объект этого класса должен быть равным объекту класса String, текстовое содержание которого равно текстовому содержанию сравниваемого объекта SpaceInsensitiveString, где последовательности пробелов заменены единичными пробелами. I>Задача опять же непротиворечива, но отсутствие мультиметодов делает ее решение невозможным.
Вообще-то, задачи типа "сравнивать строки хитровыдуманным способом" легко решаются иначе, путем введения статического метода/класса стратегии.
Нет никакой нужды для решения этой конкретной задачи вводить свой класс строки и сравнивать его со стандартным классом.
Это я к чему: в реальном проекте описанная тобой проблема яйца выеденного не стоит.
Здравствуйте, 0x7be, Вы писали:
0>Вообще-то, задачи типа "сравнивать строки хитровыдуманным способом" легко решаются иначе, путем введения статического метода/класса стратегии. 0>Нет никакой нужды для решения этой конкретной задачи вводить свой класс строки и сравнивать его со стандартным классом. 0>Это я к чему: в реальном проекте описанная тобой проблема яйца выеденного не стоит.
Возможно. Просто привел пример показывающий ущербность популярных ООП языков. А проблемы в реальных проектах все-таки возникают, например переопределение того же equals в более реалистических ситуациях, просто проблемы эти все-таки решаемы, хоть и через одно место.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Ни при каких обстоятельствах String.Equals(object) не вернет true, если object не является экземпляром класса String.
I>Это ограничение надуманно и вызвано исключительно неполноценностью классического ООП без мультиметодов.
Это ограничение гарантирует неразрушимость штатной эквивалентности строк, что вобщем-то соответствует здравому смыслу.
Соглашусь лишь с тем, что делать эквивалентность методом экземпляра было недоразумением.
Здравствуйте, igna, Вы писали:
I>Возможно. Просто привел пример показывающий ущербность популярных ООП языков. А проблемы в реальных проектах все-таки возникают, например переопределение того же equals в более реалистических ситуациях, просто проблемы эти все-таки решаемы, хоть и через одно место.
Я достаточно много писал на C# и у меня к нему есть свои претензии, однако на ЭТУ проблему так ни разу и не наткнулся.
Здравствуйте, 0x7be, Вы писали:
0>Я достаточно много писал на C# и у меня к нему есть свои претензии, однако на ЭТУ проблему так ни разу и не наткнулся.
Здравствуйте, igna, Вы писали:
0>>Я достаточно много писал на C# и у меня к нему есть свои претензии, однако на ЭТУ проблему так ни разу и не наткнулся. I>Equals не переопределял?
Вот именно так, как пишешь ты, что бы пробросить отношение равенства между разными типами, нет.
Вообще не припомню, что бы у меня такая потребность возникала хоть раз.
А для более прямолинейных сценариев переопределял и весьма успешно.
Здравствуйте, 0x7be, Вы писали:
0>А для более прямолинейных сценариев переопределял и весьма успешно.
Ну так оно же и "для более прямолинейных сценариев" через одно место. Даже при минимуме собственно логики сравнения все-равно строк десять вокруг да около.
Здравствуйте, igna, Вы писали:
I>Ну так оно же и "для более прямолинейных сценариев" через одно место. Даже при минимуме собственно логики сравнения все-равно строк десять вокруг да около.
Да, ну, брось. Даже в самом наивном сценарии это +4 строки на проверку типа и typecast:
public override bool Equals(object other)
{
if (!(other is MyType))
{
return false;
}
var myTypeOther = (MyType)other;
.... твой код
}
Но этот паттерн можно устранить, введя дополнительную функцию:
public static bool EqualsHelper<T>(this object other, Func<T, bool> predicate)
{
return other is T ? predicate((T)other) : false;
}
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Соглашусь лишь с тем, что делать эквивалентность методом экземпляра было недоразумением.
I>Ну так это уже полдела! Чем же его надо было делать, статическим методом?
Тут возможны варианты. Вполне ожидаем был бы объект, реализующий IComparer.
I>Как тогда искать в коллекции объектов?
Во-первых мне довольно сложно представить задачу, решением которой был бы поиск непонятно чего в коллекции непонятно чего. Скажем так, валить в одну коллекцию кнопки, строки, делегаты и файлы — форменное безумие. В остальном же несложно указать методу поиска соответствующий способ сравнения объектов.
Что касается форменного безумия — и эту задачу можно было решить красиво на уровне проектирования фреймворка. Например, можно было бы к типу объекта каким-то образом привязать дефаултный компарер для экземпляров этого типа. Возможно атрибутом (как конвертер типа) или виртуальным методом
IComparer Object.GetDefaultComparer()
Тогда для поиска неизвестно чего среди коллекции неизвесно чего можно было бы запросить компарер для искомого объекта и искать этим компарером. Результат был бы не хуже, чем при существующем дизайне. В частности, можно было бы построить эквивалентность для строк и SpaceInsensitiveString, но отличную от эквивалентности строк. Компарер с указанной эквивалентностью можно подать в любой метод поиска. Только не рассказывай что задача требует найти строку среди коллекции неизвестно чего, в чем может быть SpaceInsensitiveString, и об этом не знает программист, который делает вызов поиска, и ему в голову не приходит подсунуть соответствующий компарер. Попробуй выдумать не высосанную из пальца задачу, которая бы потребовала такого решаения.
Кстати, ничто не мешает писать свои IComparer и сейчас. Нужно только что бы откипело желание ломать эквивалентность чего-либо, написанного не тобой (в том числе стандартных строк).
Здравствуйте, igna, Вы писали:
I>Задача (Java): Определить класс EqualToTheObject, экземпляр которого ссылается на экземпляр класса Object, и переопределяет equals таким образом, что equals возвращает true тогда и только тогда, когда его аргумент является тем же экземпляром класса Object, на который ссылается this, или экземпляром класса EqualToTheObject ссылающегося на тот же экземпляр класса Object, на который ссылается this.
I>Отношение эквивалентности должно является рефлексивным, симметричным и транзитивным, но симметричным его похоже на Java сделать не удастся. То есть задача непротиворечива, но отсутствие мультиметодов делает ее решение невозможным.
I>Аналогично для .NET.
I>Если так, то вся эта сраная единая Java/.NET иерархия классов ущербна в самом своем корне.
То, что классовая иерархия создает не мало проблем — спору нет. Но и мультиметоды тоже не так уж и пушисты. Посмотрите на кложуру. Там без фанатизма к ним относятся, говорят, что не всегда они удобны, они могут и существенно код усложнить, запутать. Кроме того, создают они и технические проблемы — проседание по перфомансу, что не дает возможность реализовать кложуру на кложуре. Недавно им ввели альтернативу — протоколы для типов. Там диспетчеризация — только по первому параметру. Но классов и ООП в кложуре не требуют (классы там, фактически, только для дружбы с жабой), типы и протоколы похожи на структуры и интерфейсы (как в Go), или на хаскелевские классы типов. Концептуально выглядят симпатично, кложуровцы очень как бы намекают, что смотреть лучше именно на протоколы, и не только из-за лучшей производительности.
S>Во-первых мне довольно сложно представить задачу, решением которой был бы поиск непонятно чего в коллекции непонятно чего.
очень просто -- коллекция непонятно чего появляется как результат сериализации всего для записи на диск
т.е. есть у нас сериализованная-на-диск-фигня -- ну допустим целая вкладка браузера с огромной кучей классов, отвечающих за ui, html, css, историей запросов (чтобы было десериализовав пройти назад)... и вот захотелось нам найти что-то там конкретное
S>>Во-первых мне довольно сложно представить задачу, решением которой был бы поиск непонятно чего в коллекции непонятно чего.
ME>очень просто -- коллекция непонятно чего появляется как результат сериализации всего для записи на диск
На сколько я понимаю процесс сериализации, результатом его является коллекция понятно чего — байт.
ME>т.е. есть у нас сериализованная-на-диск-фигня -- ну допустим целая вкладка браузера с огромной кучей классов, отвечающих за ui, html, css, историей запросов (чтобы было десериализовав пройти назад)... и вот захотелось нам найти что-то там конкретное
найти что-то конкретное в потоке байт — не вопрос. Надо только знать, что искать. Но смысл такого поиска от меня ускользает.
Предположу что задача состоит в том что бы найти что-то конкретное в коллекции десериализованной фигни. Не могу удержаться от комментария на тему "нафига было пихать всю фигню в одну коллекцию".
Так вот, что бы что-то найти (с помощью Object.Equals) нужно очень конкретно знать, что мы ищем. Правильный Equals должен быть устроен так, что бы мы не просто могли найти класс, отвечающий за ui, а что бы мы могли отличать один класс, отвечающий за ui от другого.
a) Если это не так, то уместен вопрос, а нафига нужно было такую эквивалентность запихивать в Equals? Ведь нам нужно найти что-то, в действительности не равное конкретному экземпляру, а удовлетворяющее некоторому свойству (или свойсту типа), т.е. collection.Find(v => v is IMyUI). Использовать для такого рода поиска перекрытый Equals — очень неудачное решение.
b) В свою очередь, если нужно найти конкретную фигню с конкретными свойствами корректно равную заданной фигне, то видимо что конкретно заданная фигня у нас уже есть, именно ее мы будем искать в коллекции. Но такой поиск много смысла не имеет, он может ответить лишь на вопрос, а есть ли такая фигня в коллекции, какой у нее индекс. Отвечать на такой вопрос можно куда более эффективно, если информация будет организована чуть лучше, чем коллекция всякой фигни.
Т.е. тема "нафига нужна коллекция всякой фигни и поиск в ней именно по equals" не раскрыта.