Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dart int and double being interned? Treated specially by identical()?

Dart has both:

  • an equality operator == and
  • a top-level function named identical().

By the choice of syntax, it feels natural to want to use Dart's == operator more frequently than identical(), and I like that. In fact, the Section on Equality of the Idiomatic Dart states that "in practice, you will rarely need to use" identical().

In a recent answer to one of my questions concerning custom filters, it seems that Angular Dart favors use of identical() rather than == when trying to determine whether changes to a model have reached a steady state. (Which can make sense, I suppose, for large models for reasons of efficiency.)

This got me to thinking about identity of int's and so I wrote some tests of identical() over ints. While I expected that small ints might be "interned/cached" (e.g. similar to what is done by Java's Integer.valueOf()), to my surprise, I can't seem to generate two ints that are equal but not identical. I get similar results for double.

Are int and double values being interned/cached? Or maybe identical() is treating them specially? Coming from a Java background, I used to equate equate Dart's:

  • == to Java's equal() method and
  • identical() to Java's equality test ==.

But that now seems wrong. Anyone know what is going on?

like image 958
Patrice Chalin Avatar asked Jan 27 '14 20:01

Patrice Chalin


2 Answers

Numbers are treated specially. If their bit-pattern is the same they must be identical (although it is still debated if this includes the different versions of NaNs).

The main reasons are expectations, leaking of internal details and efficiency.

Expectations: users expect numbers to be identical. It goes against common sense that x == y (for two integers) but not identical(x, y).

Leaking of internal details: the VM uses SMIs (SMall Integers) to represent integers in a specific range (31 bits on 32-bit machines, 63 on 64-bit machines). These are canonicalized and are always identical. Exposing this internal implementation detail would lead to inconsistent results depending on which platform you run.

Efficiency: the VM wants to unbox numbers wherever it can. For example, inside a method doubles are frequently moved into registers. However, keeping track of the original box can be cumbersome and difficult.

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

Suppose, that the VM optimizes this function and moves result into a register (unboxing x in the process). This allows for a tight loop where result is then efficiently modified. The difficult case happens, when y is 0. The loop wouldn't execute and foo would return x directly. In other words, the following would need to be true:

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

If the VM unboxed the result variable in the method foo it would need to allocate a fresh box for the result and the identical call would therefore return false.

By modifying the definition of identical all these problems are avoided. It comes with a small cost to the identical check, though.

like image 71
Florian Loitsch Avatar answered Sep 25 '22 15:09

Florian Loitsch


Seems like I posted too quickly. I just stumbled on Dart Issue 13084: Spec says identical(1.0, 1) is true, even if they have different types which led me to the Dart section on Object Identity of the language spec. (I had previously search for equality in the spec but not object identity.)

Here is an excerpt:

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: ...

and there are more clauses dealing with lists, maps and constant objects. See the language spec for the full details. Hence, identical() is much more than just a simple test for reference equality.

like image 39
Patrice Chalin Avatar answered Sep 23 '22 15:09

Patrice Chalin