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

dart2js and spec disagree about numerics #1533

Closed
sethladd opened this Issue Feb 4, 2012 · 23 comments

Comments

Projects
None yet
@sethladd
Member

sethladd commented Feb 4, 2012

The following Dart code:

var x = 123;
print(x is! double);

will print TRUE in Dart VM and FALSE in JavaScript compiled from Frog.

The generated JavaScript code in question:

print((typeof(x) != 'number'));

doesn't match the intention of the original Dart code.

@DartBot

This comment has been minimized.

Show comment
Hide comment
@DartBot

DartBot Feb 4, 2012

This comment was originally written by jat@google.com


See also issue #638 and lengthy discussions on the mailing list last year.

DartBot commented Feb 4, 2012

This comment was originally written by jat@google.com


See also issue #638 and lengthy discussions on the mailing list last year.

@dgrove

This comment has been minimized.

Show comment
Hide comment
@dgrove

dgrove Feb 5, 2012

Member

Added Area-Frog, Triaged labels.

Member

dgrove commented Feb 5, 2012

Added Area-Frog, Triaged labels.

@gbracha

This comment has been minimized.

Show comment
Hide comment
@gbracha

gbracha Mar 6, 2012

Contributor

I'm generalizing this to tack the numeric discrepancies between the spec (and VM) and the Javascript based implementations.

Consider:

main() {
    int billion = 1000000000;
    int quintillion = billion * billion;
    int quintillionOne = quintillion + 1;
    print(quintillion == quintillionOne);
  }

It compiles without emitting a warning or error, and prints true, which clearly violates the principle of least astonishment.

WE may end up making allowances for JS in some way, but for now this is a bug, and we can track the issue here.


Changed the title to: "Frog and spec disagree about numerics".

Contributor

gbracha commented Mar 6, 2012

I'm generalizing this to tack the numeric discrepancies between the spec (and VM) and the Javascript based implementations.

Consider:

main() {
    int billion = 1000000000;
    int quintillion = billion * billion;
    int quintillionOne = quintillion + 1;
    print(quintillion == quintillionOne);
  }

It compiles without emitting a warning or error, and prints true, which clearly violates the principle of least astonishment.

WE may end up making allowances for JS in some way, but for now this is a bug, and we can track the issue here.


Changed the title to: "Frog and spec disagree about numerics".

@anders-sandholm

This comment has been minimized.

Show comment
Hide comment
@anders-sandholm

anders-sandholm Jun 8, 2012

Member

Removed Area-Frog label.
Added Area-Dart2JS, FromAreaFrog labels.

Member

anders-sandholm commented Jun 8, 2012

Removed Area-Frog label.
Added Area-Dart2JS, FromAreaFrog labels.

@kasperl

This comment has been minimized.

Show comment
Hide comment
@kasperl

kasperl Jun 12, 2012

Contributor

Removed FromAreaFrog label.
Changed the title to: "dart2js and spec disagree about numerics".

Contributor

kasperl commented Jun 12, 2012

Removed FromAreaFrog label.
Changed the title to: "dart2js and spec disagree about numerics".

@DartBot

This comment has been minimized.

Show comment
Hide comment
@DartBot

DartBot Jul 25, 2012

This comment was originally written by la...@randompage.org


We need arbitrary precision integers in our Dart program and have currently implemented our own integer class to get around this bug. Arbitrary precision makes sense for a modern programming language as it's would cause numeric overflows to be a thing of the past.

At any rate please provide some closure on if Dart's integers are arbitrary precision or not.

DartBot commented Jul 25, 2012

This comment was originally written by la...@randompage.org


We need arbitrary precision integers in our Dart program and have currently implemented our own integer class to get around this bug. Arbitrary precision makes sense for a modern programming language as it's would cause numeric overflows to be a thing of the past.

At any rate please provide some closure on if Dart's integers are arbitrary precision or not.

@sethladd

This comment has been minimized.

Show comment
Hide comment
@sethladd

sethladd Jul 25, 2012

Member

The spec says that integers are arbitrary precision. The open issue is how will dart2js accomplish this, with reasonable performance.

Member

sethladd commented Jul 25, 2012

The spec says that integers are arbitrary precision. The open issue is how will dart2js accomplish this, with reasonable performance.

@floitschG

This comment has been minimized.

Show comment
Hide comment
@floitschG

floitschG Aug 13, 2012

Contributor

Issue #4478 has been merged into this issue.

Contributor

floitschG commented Aug 13, 2012

Issue #4478 has been merged into this issue.

@sethladd

This comment has been minimized.

Show comment
Hide comment
@sethladd

sethladd Aug 14, 2012

Member

Added this to the M1 milestone.
Removed Priority-Medium label.
Added Priority-High label.

Member

sethladd commented Aug 14, 2012

Added this to the M1 milestone.
Removed Priority-Medium label.
Added Priority-High label.

@kasperl

This comment has been minimized.

Show comment
Hide comment
@kasperl

kasperl Aug 15, 2012

Contributor

We do not plan to change the way we deal with ints in dart2js for M1. We will take a look at tackling issue #3814 and issue #4437, but general big int support is not something we're ready to tackle anytime soon.

It remains an issue so I'm certainly keeping the bug open.


Set owner to @kasperl.
Removed this from the M1 milestone.
Added this to the Later milestone.
Removed Priority-High label.
Added Priority-Medium, Accepted labels.

Contributor

kasperl commented Aug 15, 2012

We do not plan to change the way we deal with ints in dart2js for M1. We will take a look at tackling issue #3814 and issue #4437, but general big int support is not something we're ready to tackle anytime soon.

It remains an issue so I'm certainly keeping the bug open.


Set owner to @kasperl.
Removed this from the M1 milestone.
Added this to the Later milestone.
Removed Priority-High label.
Added Priority-Medium, Accepted labels.

@kasperl

This comment has been minimized.

Show comment
Hide comment
@kasperl

kasperl Aug 15, 2012

Contributor

cc @larsbak.

Contributor

kasperl commented Aug 15, 2012

cc @larsbak.

@floitschG

This comment has been minimized.

Show comment
Hide comment
@floitschG

floitschG Oct 12, 2012

Contributor

Issue #5827 has been merged into this issue.

Contributor

floitschG commented Oct 12, 2012

Issue #5827 has been merged into this issue.

@kasperl

This comment has been minimized.

Show comment
Hide comment
@kasperl

kasperl Oct 17, 2012

Contributor

Removed this from the Later milestone.

Contributor

kasperl commented Oct 17, 2012

Removed this from the Later milestone.

@kasperl

This comment has been minimized.

Show comment
Hide comment
@kasperl

kasperl Oct 17, 2012

Contributor

Added this to the Later milestone.

Contributor

kasperl commented Oct 17, 2012

Added this to the Later milestone.

@DartBot

This comment has been minimized.

Show comment
Hide comment
@DartBot

DartBot Nov 9, 2012

This comment was originally written by ngeoffray@google.com


Issue #6627 has been merged into this issue.


cc @karlklose.

DartBot commented Nov 9, 2012

This comment was originally written by ngeoffray@google.com


Issue #6627 has been merged into this issue.


cc @karlklose.

@fsc8000

This comment has been minimized.

Show comment
Hide comment
@fsc8000

fsc8000 Nov 9, 2012

Member

Issue #6627 has been merged into this issue.

Member

fsc8000 commented Nov 9, 2012

Issue #6627 has been merged into this issue.

@rakudrama

This comment has been minimized.

Show comment
Hide comment
@rakudrama

rakudrama Nov 9, 2012

Member

Issue #6627 has been merged into this issue.

Member

rakudrama commented Nov 9, 2012

Issue #6627 has been merged into this issue.

@peter-ahe-google

This comment has been minimized.

Show comment
Hide comment
@peter-ahe-google

peter-ahe-google Dec 18, 2012

Contributor

Issue #7488 has been merged into this issue.

Contributor

peter-ahe-google commented Dec 18, 2012

Issue #7488 has been merged into this issue.

@gramster

This comment has been minimized.

Show comment
Hide comment
@gramster

gramster Dec 18, 2012

For the record, I would like to note that merging bugs like 7488 and others with 1533 is fine as long as those other bugs are revisited when addressing this issue, as this issue seems to have largely become about whether dart2js will support bigints, and I don't think that that is the same as what issue #7488 is about, namely doubles without fractional parts being treated as ints by dart2js (and thus being legitimately used, for example, as indices into containers, while the VM will throw an exception).

gramster commented Dec 18, 2012

For the record, I would like to note that merging bugs like 7488 and others with 1533 is fine as long as those other bugs are revisited when addressing this issue, as this issue seems to have largely become about whether dart2js will support bigints, and I don't think that that is the same as what issue #7488 is about, namely doubles without fractional parts being treated as ints by dart2js (and thus being legitimately used, for example, as indices into containers, while the VM will throw an exception).

@sigmundch

This comment has been minimized.

Show comment
Hide comment
@sigmundch

sigmundch Dec 9, 2015

Member

I don't believe this is something we will change in dart2js. We need to map both int/double to Number to be able to generate code that performs well in JS engines.

We might want to be more explicit/upfront about these exceptions though. Either by making mention of them in the spec or in our documentation. Thoughts?

/cc @floitschG @kwalrath @gbracha

Member

sigmundch commented Dec 9, 2015

I don't believe this is something we will change in dart2js. We need to map both int/double to Number to be able to generate code that performs well in JS engines.

We might want to be more explicit/upfront about these exceptions though. Either by making mention of them in the spec or in our documentation. Thoughts?

/cc @floitschG @kwalrath @gbracha

@homer-jay

This comment has been minimized.

Show comment
Hide comment
@homer-jay

homer-jay Jan 9, 2018

I'm new to Dart and I find the documentation extremely confusing. On the one hand it claims Dart has built in arbitrary precission integers, and this would actually be a plus for developers coming from other languages, something that might motivate them to learn Dart. On the other hand, this pad proves otherwise. In the end this pad shows a problem with numbers greater than JavaScript's MAX_SAFE_INTEGER.

Why is this discrepancy between "VM Dart" and "JS Dart" allowed to exist nowadays? Dart is Dart and it should behave the same in all platforms. Either remove big int support from the VM or add it to dart2js for the sake of sanity. It is not difficult to implement this in dart2js, just use JavaScript's Number type for safe integers and switch to a JS based big int implementation outside of that range. That way you could keep the current performance for safe integers.

homer-jay commented Jan 9, 2018

I'm new to Dart and I find the documentation extremely confusing. On the one hand it claims Dart has built in arbitrary precission integers, and this would actually be a plus for developers coming from other languages, something that might motivate them to learn Dart. On the other hand, this pad proves otherwise. In the end this pad shows a problem with numbers greater than JavaScript's MAX_SAFE_INTEGER.

Why is this discrepancy between "VM Dart" and "JS Dart" allowed to exist nowadays? Dart is Dart and it should behave the same in all platforms. Either remove big int support from the VM or add it to dart2js for the sake of sanity. It is not difficult to implement this in dart2js, just use JavaScript's Number type for safe integers and switch to a JS based big int implementation outside of that range. That way you could keep the current performance for safe integers.

@peter-ahe-google

This comment has been minimized.

Show comment
Hide comment
@peter-ahe-google

peter-ahe-google Jan 9, 2018

Contributor

@homer-jay try reaching out in one of these place: https://www.dartlang.org/community
In particular, I think this mailing list is a great place to ask questions like this: https://groups.google.com/a/dartlang.org/forum/#!forum/misc

Contributor

peter-ahe-google commented Jan 9, 2018

@homer-jay try reaching out in one of these place: https://www.dartlang.org/community
In particular, I think this mailing list is a great place to ask questions like this: https://groups.google.com/a/dartlang.org/forum/#!forum/misc

@ds84182

This comment has been minimized.

Show comment
Hide comment
@ds84182

ds84182 Jan 25, 2018

For anyone else who runs into issues with shifts with Dart2JS and DDC, there's a simple solution.

After doing any bitwise operation on a negative number the resulting number is an unsigned 32-bit integer. You can turn it into a signed 32-bit integer with .toSigned(32). Right shifts properly move the sign bit, but the sign in the JavaScript number gets discarded by Dart2JS and DDC. print(((-1 >> 1).toSigned(32) >> 1).toSigned(32)) yields -1 in both the VM (with and without big ints) and the web.

However, I do feel that this should be fixed. Since the VM is now moving to signed 64-bit integers, it would make sense to use at least signed 32-bit integers for bit operations on the web.

With some tests on Chrome and Edge, the result of ((-1) >> 1) << 0 (in JavaScript) preserves the sign bit, while ((-1) >> 1) >>> 0 (in JavaScript) (which is what Dart2JS and DDC emit) does not preserve the sign bit. Changing the latter to the former would give the web the same results that the VM would yield (at least when bit width isn't taken into account), and the web would be consistent with the behaviors JavaScript developers expect (-1 >> 1 yields -1 in JavaScript and 4294967295 in Dart compiled JavaScript).

This may become more of an issue in the future, so it would be great to know how much code depends on this weird behavior.

But anyways, I thought of some pros and cons.

Pros:

  • Unknown! I'd love to hear from someone who works on Dart2JS or DDC on why we have these differences!

Cons:

  • From a glance at code available on GitHub, most libraries use workarounds to get consistent behavior with bitwise operations on both the VM and web.
  • This problem has affected developers for years. (This is issue number 1533 out of 31972)
  • This problem has been one of the pain points from testing on Dartium and deploying to normal browsers. (Not as much as today thanks to DDC!)
  • Sharing code between the VM and the web is tricky. Since developers have Flutter, they'll notice these differences when they try to share logic between the two. A developer might run tests solely on the Dart VM for their common library because it's quicker than running tests in the browser, but they won't hit these weird bits until they use the library on the web.
  • Result differs from JavaScript, C, C++, Rust, Go, etc.

ds84182 commented Jan 25, 2018

For anyone else who runs into issues with shifts with Dart2JS and DDC, there's a simple solution.

After doing any bitwise operation on a negative number the resulting number is an unsigned 32-bit integer. You can turn it into a signed 32-bit integer with .toSigned(32). Right shifts properly move the sign bit, but the sign in the JavaScript number gets discarded by Dart2JS and DDC. print(((-1 >> 1).toSigned(32) >> 1).toSigned(32)) yields -1 in both the VM (with and without big ints) and the web.

However, I do feel that this should be fixed. Since the VM is now moving to signed 64-bit integers, it would make sense to use at least signed 32-bit integers for bit operations on the web.

With some tests on Chrome and Edge, the result of ((-1) >> 1) << 0 (in JavaScript) preserves the sign bit, while ((-1) >> 1) >>> 0 (in JavaScript) (which is what Dart2JS and DDC emit) does not preserve the sign bit. Changing the latter to the former would give the web the same results that the VM would yield (at least when bit width isn't taken into account), and the web would be consistent with the behaviors JavaScript developers expect (-1 >> 1 yields -1 in JavaScript and 4294967295 in Dart compiled JavaScript).

This may become more of an issue in the future, so it would be great to know how much code depends on this weird behavior.

But anyways, I thought of some pros and cons.

Pros:

  • Unknown! I'd love to hear from someone who works on Dart2JS or DDC on why we have these differences!

Cons:

  • From a glance at code available on GitHub, most libraries use workarounds to get consistent behavior with bitwise operations on both the VM and web.
  • This problem has affected developers for years. (This is issue number 1533 out of 31972)
  • This problem has been one of the pain points from testing on Dartium and deploying to normal browsers. (Not as much as today thanks to DDC!)
  • Sharing code between the VM and the web is tricky. Since developers have Flutter, they'll notice these differences when they try to share logic between the two. A developer might run tests solely on the Dart VM for their common library because it's quicker than running tests in the browser, but they won't hit these weird bits until they use the library on the web.
  • Result differs from JavaScript, C, C++, Rust, Go, etc.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment