Skip to content

Neither the Dart Docs (API) nor Language Docs prominently explain JS Number semantics #42924

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

Closed
matanlurey opened this issue Aug 3, 2020 · 22 comments
Assignees
Labels
area-documentation Prefer using 'type-documentation' and a specific area label. customer-flutter customer-google3

Comments

@matanlurey
Copy link
Contributor

An internal user newer to Dart had filed a bug ~roughly to the following:

How are the data types double and int handled in AngularDart?

  int a = 1; // case 1
//   double a = 1.0; // case 2
//   double a = 1.1; // case 3 
 
  if (a is double) print('double');
  if (a is int) print('int');
}

The above snippet prints both both double and int for cases 1 and 2.
Prints double for case 3.
(Tried in https://dartpad.dev/)

I actually sort of flailed around for 10-15 minutes assuming we had docs to explain this and largely failed.

... none of these really mention anything about our number semantics. int does mention:

Note: When compiling to JavaScript, integers are restricted to values that can be represented exactly by double-precision floating point values. The available integer values include all integers between -2^53 and 2^53, and some integers with larger magnitude. That includes some integers larger than 2^63. The behavior of the operators and methods in the int class therefore sometimes differs between the Dart VM and Dart code compiled to JavaScript. For example, the bitwise operators truncate their operands to 32-bit integers when compiled to JavaScript.

... but I think honestly this is way too low-level to be useful to most users, at least as the only documentation provided..

Sources I used when helping define the problem:

@nshahan did mention the following:

https://dart.dev/guides/language/language-tour#numbers

... but that only mentions:

On the Dart VM, values can be from -263 to 263 - 1.
Dart that’s compiled to JavaScript uses JavaScript numbers, allowing values from -253 to 253 - 1.

... which again, isn't quite what I would hope we would present to users potentially new to both Dart and JS.


(At one point we also had a lint for is double, but I don't see that anywhere anymore)

@vsmenon
Copy link
Member

vsmenon commented Aug 3, 2020

@kwalrath @mit-mit @leafpetersen - any opinions on where to add this? Update the tour?

I'd prefer we describe ints / numbers as platform specific and then detail native and web semantics and differences.

@srawlins srawlins added the area-documentation Prefer using 'type-documentation' and a specific area label. label Aug 4, 2020
@eernstg
Copy link
Member

eernstg commented Aug 4, 2020

The language specification has an appendix here. The description there is of course detailed / low-level as well, so the need to describe it in the language tour or a similar location remains.

@fishythefish
Copy link
Member

fishythefish commented Aug 4, 2020

The FAQ is a little outdated and hard to find, but maybe we could include the information there as well?

Technical detail aside, the spec also isn't a convenient resource to point people to because users have to pull and compile the spec from source. (By the way, should publishing an updated spec here be part of the release process?) Also, the appendices don't currently show up in the table of contents, so I for one wasn't even aware the spec mentioned JS number semantics at all.

@kwalrath
Copy link
Contributor

kwalrath commented Aug 5, 2020

How about we document the non-web version in the language tour, pointing out that the web version has different semantics, and linking to a place under dart.dev/web that goes into these semantics. (That assumes that 80% of developers won't care about the differences; if that's wrong, then maybe we should say more/all in the language tour.)

As to how we document this, below is the original content from https://spec.dart.dev/DartLangSpecDraft.pdf. How can we simplify this to be understandable and useful to the majority of developers who need this information? I suspect that we might want to add some examples, so even if we simplify the text, this might end up longer than the spec version.


Appendix: Integer Implementations

The int type represents integers. The specification is written with 64-bit two’s
complement integers as the intended implementation, but when Dart is compiled
to JavaScript, the implementation of int will instead use the JavaScript number
type.

This introduces a number of differencs [sic]:

  • Valid values of JavaScript int are any IEEE-754 64-bit floating point number
    with no fractional part. This includes positive and negative infinity, which can
    be reached by overflowing (integer division by zero is still not allowed). Otherwise valid integer literals (including any leading minus sign) that represent
    invalid JavaScript int values cannot be compiled to JavaScript. Operations
    on integers may lose precision since 64-bit floating point numbers are limited
    to 53 significant bits.

  • JavaScript int instances also implement double, and integer-valued double
    instances also implement int. The int and double class are still separate
    subclasses of the class num, but instances of either class that represent an integer act as if they are actually instances of a common subclass implementing
    both int and double. Fractional numbers only implement double.

  • Bitwise operations on integers (and, or, xor, negate and shifts) all truncate
    the operands to 32-bit values.

  • The identical method cannot distinguish the values 0.0 and −0.0, and it
    cannot recognize any NaN value as identical to itself. For efficiency, the
    identical operation uses the JavaScript === operator.

@kwalrath
Copy link
Contributor

kwalrath commented Aug 5, 2020

The FAQ is a little outdated and hard to find, but maybe we could include the information there as well?

Good idea. Would you happen to have time to update the FAQ or just tell @kevmoo and me where you noticed it being outdated?

@fishythefish
Copy link
Member

It's just that the top of the FAQ says it was last updated over a year ago and the very first question points to the Dart 1 spec, so I wasn't sure if we were still actively maintaining it as a resource. It's also a little tricky to find (without Googling "dart faq") - I think the shortest path from dart.dev requires you to click on "Docs", expand the "Resources" menu on the left, and find it nestled between "Code of conduct" and "History".

@vsmenon
Copy link
Member

vsmenon commented Aug 5, 2020

I'd like to make sure we don't give folks the impression that Dart on the Web isn't "real" Dart. I personally think of it more akin to platform specific int in C. I.e., Dart requires certain properties of int, but leaves others as implementation dependent with explanation of what that means in practice.

@eernstg
Copy link
Member

eernstg commented Aug 6, 2020

@fishythefish wrote:

users have to pull and compile the spec from source.

The 'In-progress specification' section does actually have a link to a PDF which is updated whenever the LaTeX source is updated, which is also the document that @kwalrath mentioned. I used a link into the source because it is difficult to link to a specific location in a PDF file.

Note that this appendix is just about to be updated to describe the actual behavior of bit operations (it's unsigned rather than signed), cf. #42892.

@vsmenon wrote:

I'd like .. Dart requires certain properties of int, but leaves others as implementation dependent

That would be a very nice approach to take. However, it goes somewhat deep. For instance, int and double are specified to have no subtypes (other than bottom types), and the new treatment of number types relies on this property in order to be able to conclude that the type of a + b is int in some cases depending on the type of a and the type of b. It still works in the case where a and b have both types int and double, given that the + operation will produce an int when it adds two ints. But we don't have anything like a nice, regular design space that we can leave open as implementation specific.

@vsmenon
Copy link
Member

vsmenon commented Aug 6, 2020

@eernstg wrote:

That would be a very nice approach to take. However, it goes somewhat deep. For instance, int and double are specified to have no subtypes (other than bottom types), and the new treatment of number types relies on this property in order to be able to conclude that the type of a + b is int in some cases depending on the type of a and the type of b. It still works in the case where a and b have both types int and double, given that the + operation will produce an int when it adds two ints. But we don't have anything like a nice, regular design space that we can leave open as implementation specific.

Does the newly spec'ed behavior work out when compiling to JS? I had understood to be largely orthogonal: it doesn't say anything about precision, and it's about static typing.

Are the runtime types we produce on the Web sound wrt the static types in the spec?

@eernstg
Copy link
Member

eernstg commented Aug 6, 2020

Does the newly spec'ed behavior work out when compiling to JS?

Yes, but it depends on the details of the treatment of numbers for JS compilation, and it's a property which can't be captured by normal type systems that an int plus an int yields an int when that is at the same time an operation which adds two double values (with exactly the same representation as when it's viewed as an int addition) and produces a double. Only a few of the values of type double have type int as well, and the type system doesn't understand that those special values always produce the same kind of special values when added.

Are the runtime types we produce on the Web sound wrt the static types in the spec?

Yes.

@fishythefish
Copy link
Member

The 'In-progress specification' section does actually have a link to a PDF which is updated whenever the LaTeX source is updated

Oh, awesome, I knew we had the 2.2 version; I didn't realize we had an updated one on the site as well.

@kwalrath
Copy link
Contributor

kwalrath commented Aug 6, 2020

Oh, awesome, I knew we had the 2.2 version; I didn't realize we had an updated one on the site as well.

I should reorg that page to make the in-progress spec easier to find.

@leafpetersen
Copy link
Member

For instance, int and double are specified to have no subtypes (other than bottom types), and the new treatment of number types relies on this property in order to be able to conclude that the type of a + b is int in some cases depending on the type of a and the type of b.

This is not true on any platform that we ship. On every platform that I'm aware of, int has multiple subtypes. I'm highly skeptical that our treatment of numbers is incompatible with there being a common implementation type which implements both the int and the double type. Do you have a counter-example in mind?

@eernstg
Copy link
Member

eernstg commented Aug 7, 2020

@leafpetersen wrote:

On every platform that I'm aware of, int has multiple subtypes

The specified constraint is that

It is a compile-time error for a class to extend, mix in or implement \code{int}.
It is a compile-time error for a class to extend, mix in or implement \code{double}.
It is a compile-time error for any class other than \code{int} and \code{double}
to extend, mix in or implement \code{num}.

Implementations may still have representations that differ (such as SMIs and heap allocated integers), but I believe that there is no way for a Dart program to associate those representations with a proper subtype of int. So they are 'subtypes' in a very special manner that the Dart type system doesn't know about.

I'm highly skeptical that our treatment of numbers is incompatible with there
being a common implementation type which implements both the int and the double type

I think it is compatible, which is the reason why I said 'yes' in response to the question about soundness for numbers.

Let's call that common (very special) type IEEE754number. The ability to give a + b the type int when a and b have the type int in the setting where they are actually both instances of IEEE754number relies on the detailed properties addition with such numbers. So we happen to say that it's an int when it represents a pseudo-real number whose fractional part is zero, and such numbers happen to yield yet another such number when we add them (including the case where the result is +/- infinity).

But type systems cannot capture this property (except perhaps for Coq style dependent types with a detailed description of IEEE 754 addition etc, but anything similar to the Dart type system definitely cannot capture it). So we could replace the IEEE 754 addition by some other computation where 1 plus 1 yields 3.14, and it would then be unsound to give 1 + 1 the type int. The point is that the type system would not have the information needed in order to make that distinction, we are simply promising that the implementation of + which is being used has that property.

That's the reason why I'm saying that we don't have a nice, well-specifiable language design space where we can just say "here are a couple of rules about int and double, and the rest is up to the implementation". But when we limit ourselves to a very carefully selected set of special cases, we can make sure that it works.

@vsmenon
Copy link
Member

vsmenon commented Aug 17, 2020

I think the overall goals here are:
(a) Explain what Dart programmers can assume about numbers on any platform.
(b) Explain the specific differences between vm and web.

This might not belong in the spec.

@kwalrath
Copy link
Contributor

I think the overall goals here are:
(a) Explain what Dart programmers can assume about numbers on any platform.
(b) Explain the specific differences between vm and web.

This might not belong in the spec.

I'd be happy to cover it in the language tour or somewhere else on dart.dev, but I need the right simple, helpful words to use. We can always refer to this issue for the full discussion.

Anyone interested in helping me get the words?

Or in creating a PR yourself? (Just click the doc link at the upper right of the appropriate page...)

@eernstg
Copy link
Member

eernstg commented Aug 18, 2020

Anyone interested in helping me get the words?

I can do that. I think it would be helpful to describe native numbers and JS numbers separately, and then the part about what Dart programmers can assume could be extracted from that. I'll get in touch via email.

@eernstg
Copy link
Member

eernstg commented Feb 25, 2021

@kwalrath, @vsmenon, it's been a while—did this issue get subsumed by the 'Numbers in Dart' document?

@kwalrath
Copy link
Contributor

Yes, pretty much. We plan to publish that article within a month. Then I'll be able to update the docs to summarize and refer to it.

@eernstg
Copy link
Member

eernstg commented Feb 25, 2021

OK, thanks! Then I won't worry about this unless I hear more.

@thecalamiity
Copy link

@kwalrath I think this can be closed now.

@mit-mit
Copy link
Member

mit-mit commented Aug 5, 2021

It indeed can; we now have https://dart.dev/guides/language/numbers

@mit-mit mit-mit closed this as completed Aug 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-documentation Prefer using 'type-documentation' and a specific area label. customer-flutter customer-google3
Projects
None yet
Development

No branches or pull requests

9 participants