Почему Kotlin использует == для структурного равенства и вводит === для ссылочного равенства - PullRequest
3 голосов
/ 20 марта 2019

В целом, каждое дизайнерское решение в Kotlin кажется само по себе прекрасным и предлагает хороший переход с Java. Как разработчик Java, вы можете начать программировать в нем, думая о Kotlin как о более сжатой Java с меньшим количеством шаблонов, а затем плавно перейти к более сложным аспектам, таким как функциональное программирование.

Единственное, что меня интересует, это то, почему его дизайнеры решили заставить == вести себя идентично equals, а затем ввести === для проверки ссылочного равенства. Я могу представить, как пытаюсь привлечь других разработчиков Java, чтобы они увидели ваш код Kotlin и подумали: «О нет, повсюду, где это должен быть равный вызов, есть проверки ссылок!»

Какой здесь мыслительный процесс для отхода от соглашения Java? Просто чтобы прояснить, я прекрасно понимаю, в чем разница между == или equals и === в Котлине, мне просто интересно, почему.

Ответы [ 2 ]

9 голосов
/ 20 марта 2019

Основная причина, вероятно, заключается в том, что равенство объектов проверяется гораздо чаще, чем идентичность объектов, поэтому это должно быть как минимум так же просто.

Я не видел однозначного утверждения по этому поводу. Но в книге Kotlin In Action есть указатель от членов команды Kotlin. Раздел 4.3.1, вводящий оператор ==, сначала описывает сравнения Java и говорит, что:

В Java существует общепринятая практика всегда вызывать equals, и есть известная проблема забывать это делать.

В Java проверить идентичность объекта легко:

if (firstObj == secondObj)

Но проверка равенства объектов дольше и менее понятна:

if (firstObj.equals(secondObj))

- точнее, если вы не хотите рисковать NullPointerException:

if ((firstObj == null) ? (secondObj == null) : firstObj.equals(secondObj))

Вы можете видеть, сколько еще боли нужно набрать, и получить правильную. (Особенно, когда один из этих объектов является выражением с побочными эффектами…)

Так что легко забыть разницу или не беспокоиться, и использовать вместо нее ==. (Которые могут вызывать тонкие, трудно обнаруживаемые ошибки и периодически кусаться.)

Kotlin, однако, делает наиболее распространенную операцию более простой: его оператор == проверяет равенство объектов, используя equals(), и также заботится о проверке нуля. Это исправляет «проблему забвения» в Java.

(И хотя совместимость с кодом Java явно была основной целью, JetBrains не ограничивался попыткой выглядеть как Java; Kotlin заимствует из Java, где это возможно, но не боится что-то изменить к лучшему. Вы можете видеть, что при использовании val и var и конечных типов для объявлений, различные значения по умолчанию для области видимости и открытости, различные способы обработки дисперсии и т. д.)

Одной из мотиваций Kotlin было решение многих проблем в Java. (На самом деле сравнение языков JetBrains начинается с перечисления «Некоторые проблемы Java, решаемые в Kotlin».) Таким образом, вполне вероятно, что это является основной причиной изменений.

3 голосов
/ 20 марта 2019

В дополнение к отличному ответу Гидса, есть и другие языки, кроме Java, которые сильно повлияли на Kotlin.В частности, Scala и C #.Цитата Дмитрий Джемеров (ссылка на InfoWorld, которая мне не очень нравится, но это лучший источник, который я нашел):

Мы посмотрелина всех существующих языках JVM, и ни один из них не отвечает нашим потребностям.Scala имеет правильные функции, но наиболее очевидным недостатком является очень медленная компиляция.

Очевидно, == была одной из тех функций, которые, по их мнению, были правильными, поскольку Scala работает точно так же (вплоть доимя для ссылочного равенства (eq в Scala).

И вы можете найти объяснение дизайна Scala в книге Программирование в Scala, в которой Мартин Одерский является одним изавторы:

Как упоминалось в разделе 11.2, определение равенства в Scala и Java отличается.В Java есть два сравнения на равенство: оператор ==, который является естественным равенством для типов значений и идентификатором объекта для ссылочных типов, и метод equals, который является (определяемым пользователем) каноническим равенством для ссылочных типов.Это соглашение проблематично, поскольку более естественный символ == не всегда соответствует естественному понятию равенства.При программировании на Java распространенным подводным камнем для новичков является сравнение объектов с ==, когда их следует сравнивать с равными.Например, сравнение двух строк x и y с использованием «x == y» вполне может привести к значению false в Java, даже если x и y имеют одинаковые символы в одном и том же порядке.

В Scala также есть метод равенстваозначает идентичность объекта, но он не используется много.Такое равенство, написанное «x eq y», истинно, если x и y ссылаются на один и тот же объект.== равенство зарезервировано в Scala для «естественного» равенства каждого типа.Для типов значений == - это сравнение значений, как в Java.Для ссылочных типов == - это то же самое, что и в Scala.Вы можете переопределить поведение == для новых типов, переопределив метод equals, который всегда наследуется от класса Any ...

С другой стороны, C # допускает перегрузку == отдельно от Equals, и они закончили тем, что один из языковых дизайнеров сказал

Длинный ответ заключается в том, что все это странно, и ни один из них не работает так, как в идеале.

...