Дарт инт и двойной интернированный? Лечится специально одинаковым ()?

Дарт имеет оба:

  • оператор равенства == а также
  • функция верхнего уровня с именем identical(),

По выбору синтаксиса вполне естественно хотеть использовать дартс == оператор чаще, чем identical() и мне это нравится. На самом деле, в разделе "Равенство идиоматических дротиков" говорится, что "на практике вам понадобится редко" identical(),

В недавнем ответе на один из моих вопросов, касающихся пользовательских фильтров, похоже, что Angular Dart одобряет использование identical() скорее, чем == при попытке определить, достигли ли изменения в модели устойчивого состояния. (Что может иметь смысл, я полагаю, для больших моделей по соображениям эффективности.)

Это заставило меня задуматься о личности int и так я написал несколько тестов identical() над int s. Хотя я ожидал, что маленький int s может быть "интернирован / кэширован" (например, аналогично тому, что делается в Java Integer.valueOf()), к моему удивлению, я не могу генерировать два int которые равны, но не идентичны. Я получаю похожие результаты для double,

Являются int а также double значения интернируются / кэшируются? Или, может быть identical() специально к ним относится? Исходя из фона Java, я привык приравнивать уравнение Дарт:

  • == к Яве equal() метод и
  • identical() к тесту равенства Java ==,

Но это сейчас кажется неправильным. Кто-нибудь знает, что происходит?

3 ответа

Решение

Похоже, я отправил слишком быстро. Я только что наткнулся на Dart Issue 13084: Spec говорит, что идентичные (1.0, 1) верны, даже если они имеют разные типы, что привело меня к разделу Dart об объектной идентичности спецификации языка. (Ранее я искал равенство в спецификации, но не идентичность объекта.)

Вот выдержка:

The predefined dart function identical() is defined such that identical(c1, c2) iff: 
- c1 evaluates to either null or an instance of
  bool and c1 == c2, OR 
- c1 and c2 are instances of int and c1 == c2, OR
- c1 and c2 are constant strings and c1 == c2, OR 
- c1 and c2 are instances of double and one of the following holds: ...

и есть еще пункты, касающиеся списков, карт и константных объектов. Смотрите спецификации языка для более подробной информации. Следовательно, identical() это гораздо больше, чем простой тест на равенство ссылок.

Числа обрабатываются специально. Если их битовый шаблон одинаков, они должны быть идентичными (хотя это все еще обсуждается, если это включает в себя различные версии NaN).

Основными причинами являются ожидания, утечка внутренних деталей и эффективность.

Ожидания: пользователи ожидают, что цифры будут идентичны. Это противоречит здравому смыслу, что x == y (для двух целых чисел), но не идентичны (x, y).

Утечка внутренних деталей: ВМ использует SMI (SMall Integer) для представления целых чисел в определенном диапазоне (31 бит на 32-битных машинах, 63 на 64-битных машинах). Они канонизированы и всегда идентичны. Раскрытие этой внутренней детализации может привести к противоречивым результатам в зависимости от используемой платформы.

Эффективность: виртуальная машина хочет распаковать номера, где это возможно. Например, внутри метода двойники часто перемещаются в регистры. Однако отслеживание оригинальной коробки может быть громоздким и сложным.

foo(x, y) {
  var result = x;
  while(y-- > 0) {
    result += x;
  }
  return result;
}

Предположим, что виртуальная машина оптимизирует эту функцию и перемещается result в реестр (распаковка x в процессе). Это учитывает жесткую петлю, где result затем эффективно модифицируется. Сложный случай случается, когда y равно 0. Цикл не будет выполняться и foo вернется x непосредственно. Другими словами, должно быть верно следующее:

var x = 5.0;
identical(x, foo(x, 0));  // should be true.

Если ВМ распаковала result переменная в методе foo это должно было бы выделить новую коробку для result и identical поэтому вызов будет возвращен false,

Изменяя определение identical все эти проблемы избегаются. Это идет с небольшой стоимостью identical проверьте, хотя.

Я не могу вспомнить источник этого, но где-то на dartlang.org или в трекере было сказано, что num, int а также double действительно получают специальное лечение. Одним из таких специальных методов является то, что вы не можете подклассы этих типов по причинам производительности, но может быть и больше. Что именно влечет за собой этот особый подход, вероятно, могут ответить только разработчики или кто-то, кто знает спецификацию наизусть, но можно сделать одно заключение:

Числовые типы являются объектами dart - у них есть методы, которые вы можете вызывать в их экземплярах. Но у них также есть качества примитивных типов данных, как вы можете сделать int i = 3;в то время как чистый объект должен иметь new Ключевое слово где-то. Это отличается от Java, где существуют реальные примитивные типы и реальные объекты, обертывающие их и раскрывающие методы экземпляра.

Хотя технические детали, безусловно, более сложны, если вы думаете о числах дротиков как о комбинации объектов и примитивов, ваше сравнение с Java все же имеет смысл. В Java new Integer(5).equals(new Integer(5)) оценивается как истина, и так же 5==5,

Я знаю, что это не очень технически правильный ответ, но я надеюсь, что все-таки полезно разобраться в поведении чисел дротиков, исходящих из Java-фона.

Другие вопросы по тегам