Allow web numbers in spec, make `identical` on NaNs, and zeros unspecified.
The current language specification specifies identical on doubles to be true if the doubles have the same representation.
That is, it makes it indistinguishable whether doubles are canonicalized based on their bit-pattern, or not.
The spec only says so in the constants section, where it defines constant identical, but that has generally been treated as defining how identical must work in general, since constant evaluation should have the same behavior as runtime evaluation (plus canonicalization).
However, web number semantics behave differently:
-
identical(double.nan, double.nan)is false -
identical(0.0, -0.0)is true
The former (and latter) is a consequence of using === to implement identical, instead of fx. Object.is, which would have the native number identity semantics.
The latter is also desired behavior when using doubles to represent integers, and not wanting to do extra normalization on every computation. An int x = ...; x = -x; print(identical(x, 0)) is expected to print true, but if x starts out as 0.0, and x = -x doesn't make any attempt to avoid -0.0, then a native-compatible identical would give false, contrary to expected integer semantics.
(It's non-trivial to remove -0.0 from integer operations, even if we were willing to add a +0.0 to every integer computation, because we don't always know whether something is an integer computation. If the type is num or dynamic, it might be intended as an integer operation, and it might not.)
So, should we update the language specification to make the value of those particular constant expressions unspecified? (And update the library documentation to say the same).
Effectively we make identical on those particular values undefined the same way we make identical on records undefined. The runtime may answer either true or false, and you should simply avoid using identical on NaN values, and be vary about identical on zeros.
That is:
identical(c1, c2):
ifc1andc2both evaluate todouble` values, then
- If both values are NaN values, the result can be either
trueor `false.- If one value is -0.0 and the other is 0.0, then the result can be either
trueorfalse.- Otherwise the result is
trueif the values are both non-NaN values with the same numerical (finite or infinite) value, andfalseif not.
(Stated before the rules for int values, so that it takes precedence on the web.)
That has the added benefit of making it unspecified which NaN representations are used.
Currently you can read non-canonical NaN values out of a Float64List, and it's possible to tell the difference by using identical, meaning that you can have v1.isNaN && v2.isNaN && !identical(v1, v2).
You would still have that, but it's not as surprising, since identical on NaN values can be either value anyway.
(If we want to, we could make development compilation actually randomize those values, so code doesn't accidentally depend on one particular production behavior.)
This question isn't necessarily restricted to web numbers, but in general: With the introduction of Wasm and Dart potentially compiling to Wasm to be run on JS, would different behavior appear "on the web" whether it was compiled with dart2js or dart2wasm?
I believe dart2wasm currently compiles with "native" number semantics, not JS-numbers. (So it's technically more correct to call it JS-numbers than web-numbers.)
The Wasm compiled code doesn't (necessarily) know whether it is running on the web or not, so it will differ from dart2js compiled code. (Currently the Wasm code might assume that it can use JS integration for some things. In the long run, it will probably be able to run in other environments too.)