Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

double.nan identical in CFE and not identical in dart2js #42224

Open
sgrekhov opened this issue Jun 8, 2020 · 4 comments
Open

double.nan identical in CFE and not identical in dart2js #42224

sgrekhov opened this issue Jun 8, 2020 · 4 comments
Labels
area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. dart2js-compile-time dev-compiler-sdk web-dart2js web-dev-compiler

Comments

@sgrekhov
Copy link
Contributor

sgrekhov commented Jun 8, 2020

The code below works in CFE and fails in dart2js and dartdevk

import "../../../Utils/expect.dart";

main() {
  Expect.isFalse(double.nan == double.nan);
  Expect.isTrue(identical(double.nan, double.nan)); // fail in dart2js
}

Dart VM version: 2.9.0-13.0.dev (dev) (Fri May 29 15:59:05 2020 +0200) on "windows_x64"

@eernstg eernstg added area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. dart2js-compile-time dev-compiler-sdk labels Jun 8, 2020
@eernstg
Copy link
Member

eernstg commented Jun 8, 2020

identical for nan values is true when the two given values have the same bit pattern (cf. https://stackoverflow.com/questions/19800415/why-does-ieee-754-reserve-so-many-nan-values#:~:text=The%20IEEE%2D754%20standard%20defines,the%20payload%20of%20the%20NaN.), so in general we can't expect two values representing not-a-number to be identical.

However, the declaration of double.nan is a constant variable, so it would be expected to yield the exact same bit pattern every time it is evaluated, unless double.nan is given some special treatment during compilation.

I think this should be labeled as a dart2js and dartdevk issue, and then the team can consider whether this is the expected behavior. It's not obvious which labels fit the bill, but double is an sdk class and the variable is constant, so 'dart2js-compile-time' and 'dev-compiler-sdk' seem to be the most relevant ones.

@lrhn
Copy link
Member

lrhn commented Jul 14, 2022

JavaScript has Object.is which has the precise behavior we want for identical in Dart. We should use that instead of ===.
(Can't make it as short, even with a one-character alias, it's still four characters to do _(e1,e2) instead of three for e1===e2.)

The Object.is function correctly identifies NaN, -0.0 and 0.0. It otherwise works like === for non-numbers.

(Actually, Object.is does not distinguish NaNs with different payloads, but the JavaScript specification generally ignores that those can exist, and some JavaScript implementations actively prevents them.)

@sigmundch
Copy link
Member

/cc @rakudrama

@rakudrama
Copy link
Member

Object.is is interesting.

We would have to check that it has good performance on all relevant implementations. It is unlikely to be as efficient, e.g. V8 compiles === to a byte-code, but calling Object.is a call.

Object.is is not a perfect fit for other reasons.

null

Both JavaScript null and undefined are used to represent Dart null. Today we handle this be choosing between a === b and a == null ? b == null : a === b, with the second being used when both a and b are possibly null. We could do something similar with Object.is.

DDC manages to mostly avoid undefined, but at some cost. For example, new Array(10) is replaced by new Array(10).fill(null). There is more on this topic at #36116

-0.0

0.0 are -0.0 are both possible as the result of integer arithmetic. This is a consequence of making int.unary-, double.unary- and num.unary- consistent - when the receiver has static type num and the value is 0, we can't tell if the intent is for int.unary- or double.unary-, so we have a single method that uses JavaScript's negation which produces -0.0. We could reverse this consistency requirement and make unary- be statically dispatched on subtypes of num.

A related problem is whether (-0.0) is int should still be true on the web. Various predicates are used depending on context. typeof o == "number" && Math.floor(o) == o or Number.isInteger(o) or o >>> 0 === o all accept -0.0. Excluding -0.0 would make all of these more expensive (i.e. adding && !Object.is(o, -0.0)).

Core library classes are not necessarily written using the expected operations. HashMaps don't use the hashCode of Strings since it is massively more efficient to use JavaScript Object with string properties as 'underlying' map. Likewise, identity maps and sets might reasonably use ES6 Maps, which treat 0 and -0.0 as the same key.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. dart2js-compile-time dev-compiler-sdk web-dart2js web-dev-compiler
Projects
None yet
Development

No branches or pull requests

6 participants