dart-lang / dart-lang/language

Allow web numbers in spec, make `identical` on NaNs, and zeros unspecified.

Open
#3,569 4 comments 0 reactions 0 assignees View on GitHub
feature specification
Dominant language
TeX
Stars
2.9k
Forks
239
Avg merge
2d 18h
Merged PRs (30d)
14

Description

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)`:
> * `if `c1` and `c2` both evaluate to `double` values, then
>
> * If both values are NaN values, the result can be either `true` or `false.
> * If one value is -0.0 and the other is 0.0, then the result can be either `true` or `false`.
> * Otherwise the result is `true` if the values are both non-NaN values with the same numerical
> (finite or infinite) value, and `false` if 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.)

Contributor guide

Open the contributing guide

Research direction

Start with the constants section of the language specification and the library documentation for identical. Compare the proposed web-number rules with the existing treatment of records, then update both references so NaN and signed-zero results are explicitly unspecified and confirm the wording preserves the stated integer semantics.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart
Domain
documentation
Issue type
Documentation
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.