Краткий ответ: последовательность
Однако, чтобы ответить на ваш вопрос правильно, я предлагаю сделать шаг назад и посмотреть на вопрос, что означает равенство в языке программирования. Существует как минимум ТРИ различных варианта, которые используются на разных языках:
- Ссылочное равенство : означает, что a = b истинно, если a и b ссылаются на один и тот же объект. Было бы неверно, если бы a и b ссылались на разные объекты, даже если все атрибуты a и b были одинаковыми.
- Неглубокое равенство : означает, что a = b истинно, если все атрибуты объектов, на которые ссылаются a и b, идентичны. Неглубокое равенство может быть легко реализовано путем побитового сравнения пространства памяти, которое представляет два объекта. Обратите внимание, что ссылочное равенство подразумевает поверхностное равенство
- Глубокое равенство : означает, что a = b истинно, если каждый атрибут в a и b либо идентичен, либо глубоко равен. Обратите внимание, что глубокое равенство подразумевается как ссылочным равенством, так и поверхностным равенством. В этом смысле глубокое равенство является самой слабой формой равенства, а ссылочное равенство является наиболее сильным.
Эти три типа равенства часто используются, потому что они удобны для реализации: все три проверки на равенство могут быть легко сгенерированы компилятором (в случае глубокого равенства, компилятору может понадобиться использовать биты тега для предотвращения бесконечных циклов, если структура сравнивать имеет круговые ссылки). Но есть другая проблема: ни один из них не может быть уместным.
В нетривиальных системах равенство объектов часто определяется как нечто между глубоким и эталонным равенством. Чтобы проверить, хотим ли мы считать два объекта равными в определенном контексте, нам может потребоваться сравнить некоторые атрибуты по тому, как они находятся в памяти, а другие по глубокому равенству, в то время как некоторым атрибутам может быть разрешено быть чем-то совершенно другим. Что нам действительно нужно, так это «четвертый тип равенства», действительно хороший, часто называемый в литературе семантическим равенством . Вещи равны, если они равны, в нашей области. знак равно
Итак, мы можем вернуться к вашему вопросу:
Есть ли какое-то главное преимущество по умолчанию в этом, которого я просто упускаю, или кажется разумным, что поведение по умолчанию должно быть логическим равенством, и возвращение по умолчанию обратно к ссылочному равенству, если логическое равенство не существует для класса?
Что мы имеем в виду, когда пишем «a == b» на любом языке? В идеале всегда должно быть одно и то же: семантическое равенство. Но это невозможно.
Одним из основных соображений является то, что, по крайней мере для простых типов, таких как числа, мы ожидаем, что две переменные равны после присвоения одного и того же значения. Увидеть ниже:
var a = 1;
var b = a;
if (a == b){
...
}
a = 3;
b = 3;
if (a == b) {
...
}
В этом случае мы ожидаем, что «a равно b» в обоих утверждениях. Все остальное было бы безумием. Большинство (если не все) языков придерживаются этого соглашения. Следовательно, с помощью простых типов (или значений) мы знаем, как достичь семантического равенства. С объектами это может быть что-то совершенно другое. Увидеть ниже:
var a = new Something(1);
var b = a;
if (a == b){
...
}
b = new Something(1);
a.DoSomething();
b.DoSomething();
if (a == b) {
...
}
Мы ожидаем, что первое «если» будет всегда верным. Но что вы ожидаете от второго «если»? Это действительно зависит. Может ли DoSomething изменить (семантическое) равенство a и b?
Проблема с семантическим равенством состоит в том, что он не может быть автоматически сгенерирован компилятором для объектов, и это не очевидно из назначений . Для пользователя должен быть предусмотрен механизм определения семантического равенства. В объектно-ориентированных языках этот механизм является унаследованным методом: равно . Читая фрагмент ОО-кода, мы не ожидаем, что метод будет иметь одинаковую точную реализацию во всех классах. Мы привыкли к наследованию и перегрузкам.
Однако с операторами мы ожидаем того же поведения. Когда вы видите «a == b», вы должны ожидать одинаковый тип равенства (из 4 выше) во всех ситуациях. Таким образом, стремясь к согласованности, разработчики языков использовали равенство ссылок для всех типов. Это не должно зависеть от того, переопределил ли программист метод или нет.
PS: язык Dee немного отличается от языка Java и C #: оператор equals означает поверхностное равенство для простых типов и семантическое равенство для пользовательских классов (с ответственностью за реализацию операции =, лежащей у пользователя - по умолчанию не предусмотрено). Так как для простых типов неглубокое равенство - это всегда семантическое равенство, язык является последовательным. Однако цена, которую он платит, заключается в том, что оператор equals по умолчанию не определен для пользовательских типов. Вы должны реализовать это. И иногда это просто скучно.