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

Let decimal literals with exponents greater or equal to the number of decimal places have static type int #909

Closed
robertbastian opened this issue Apr 1, 2020 · 15 comments
Labels
feature Proposed language feature that solves one or more problems state-rejected This will not be worked on

Comments

@robertbastian
Copy link

robertbastian commented Apr 1, 2020

[Edit, eernstg: The discussion below amounts to a proposal that some numeric literals which are currently denoting double values could be given the type int and evaluate correspondingly, as a kind of mirror image of the way we can make 0 a value of type double, based on the context. For instance, int i = 1e9; would mean the same thing as int i = 1000000000;]

The literal 10e6 has static type double. This contradicts the language spec, which (in chapter 15.3 Numbers) states:

[...] if the numeric literal does not include a decimal point it denotes a decimal integer. Otherwise, the numeric literal denotes a 64 bit double precision floating point number [...]"

An integer literal is either a hexadecimal integer literal or a decimal integer literal [...] The static type of an integer literal is int"

So by that, the static type of 10e6 should be int, because there's no decimal point (implementation bug).

However, the specification has a bug as well. According to it, the static type of 10e-6 is also int. The spec should be updated to something like

[...] if the numeric literal does not include a decimal point, and does not include a negative exponent, it denotes a decimal integer. Otherwise, the numeric literal denotes a 64 bit double precision floating point number [...]"

@robertbastian robertbastian added the bug There is a mistake in the language specification or in an active document label Apr 1, 2020
@mraleph
Copy link
Member

mraleph commented Apr 3, 2020

I think you are quoting old (pre Dart 2) specification. Current specification says the following in section 16.5:

A numeric literal starting with 0x or 0X is a hexadecimal integer literal. It has the numeric integer value of the hexadecimal numeral following 0x (respectively 0X).
A numeric literal that contains only decimal digits is a decimal integer literal. It has the numeric integer value of the decimal numeral.
An integer literal is either a hexadecimal integer literal or a decimal integer literal.
...
A numeric literal that is not an integer literal is a double literal. A double
literal always contains either a decimal point or an exponent part.
The static type
of a double literal is double.

@mraleph mraleph closed this as completed Apr 3, 2020
@mraleph mraleph removed the bug There is a mistake in the language specification or in an active document label Apr 3, 2020
@robertbastian
Copy link
Author

Oops. In any case, can we treat decimal integer literals with positive exponents as ints? Being able to express a constant as 5e7 is much more readable than 500000000.

@mdakin
Copy link

mdakin commented Apr 3, 2020

@robertbastian I think if #2 is implemented it could be better for readability of integer literals.

@robertbastian
Copy link
Author

robertbastian commented Apr 3, 2020

Yes, but I think 5e23 should be an integer as well, it is still more readable than 500_000_000_000_000_000_000_000.

@robertbastian robertbastian changed the title Specification and implementation treatment of numeric literals with exponents Let decimal literals with exponents greater or equal to the number of decimal places have static type int Apr 3, 2020
@robertbastian
Copy link
Author

robertbastian commented Apr 3, 2020

5.88e7 is also an integer, and some users might want to express numbers like this.

@mraleph
Copy link
Member

mraleph commented Apr 3, 2020

@robertbastian it would be a breaking change to treat 5e7 as an integer unconditionally. Theoretically, 5e7 could be treated as integer in context where int is expected based on static types - that does not sound too breaking.

@leafpetersen @lrhn @eernstg - Leaf/Lasse/Erik any opinion on that?

Yes, but I think 5e23 should be an integer as well

This value does not really fit into 64-bit signed integer (10^23 > 8^23 = 2^69) - so it is unclear why it would be an integer.

@robertbastian
Copy link
Author

Theoretically, 5e7 could be treated as integer in context where int is expected based on static types - that does not sound too breaking.

Isn't there already logic to treat int literals as doubles based on static typing?

This value does not really fit into 64-bit signed integer (10^23 > 8^23 = 2^69) - so it is unclear why it would be an integer.

Isn't the size of int up to the implementation, and potentially unbounded? In any case, this was an example to say that with large numbers using exponents might be preferrable to grouping digits, so this is a separate issue from #2.

@eernstg
Copy link
Member

eernstg commented Apr 3, 2020

There was strong support for allowing literals like 0 to be of type double when the context type indicates that a double is welcome but an int is not.

The point is that 0, 1, 10 and similar literals are concise, and there is no conceptual problem in thinking about those numbers as "integers by default, but doubles if needed".

We could consider literals like 1e8 similarly (that is, it's a double by default, but if the context type calls for an int and doesn't not admit a double then it's the integer 100000000). We would then reject this treatment for literals denoting numbers that are out of range (on the vm that's 64 bits signed, but it's more tricky for execution based on compilation to JavaScript because 1e308 is int also evaluates to true there—we are far away from being able to denote a non-integral value with big numbers like that).

So it looks like we could do it.

But it would definitely need to rely on the context type, because it would be seriously breaking to just say that every occurrence of 1e8 and similar literals are now of type int, and it would be slightly more delicate than the int-literal-of-type-double support that we already have (because you need to think a bit before you know whether 1e23 could be an int), so the question is whether it is actually a net benefit.

@robertbastian
Copy link
Author

Could someone reopen this bug then?

@eernstg eernstg added the feature Proposed language feature that solves one or more problems label Apr 3, 2020
@eernstg eernstg reopened this Apr 3, 2020
@lrhn
Copy link
Member

lrhn commented Apr 5, 2020

This is a duplicate of #26053.

It is breaking and it is a potentially confusing change. Other languages consistently make 1e7 a double. There is no good reason why 1.1e7 can't be an integer too, but I'd be even more worried about explaining that. What are the edge cases? Is 1e20 an integer and 1e21 a double? Also when compiled to JavaScript?

@mraleph
Copy link
Member

mraleph commented Apr 6, 2020

It is breaking and it is a potentially confusing change.

Why is it breaking? The proposal is to make 1e7 an integer in int context, similarly how we treat 0 as double if double is statically expected.

Currently if you write 1e7 in int context you get compilation error - so it should not be breaking to make that not a compilation error.

@lrhn
Copy link
Member

lrhn commented Apr 6, 2020

True, it's not breaking if only applied in an int context. Then it's only confusing, mainly because of the edge cases being non-obvious.
I'd still rather do digit separators (#2). They can also make numbers not ending in a sequence of 0 digits more readable.

@munificent
Copy link
Member

munificent commented Apr 10, 2020

I think only doing this in an int context is too brittle. It means moving a literal like 1e7 from one place to another can change its type:

expectsInt(1e7); // OK.

to:

var x = 1e7;
expectsInt(x); // Error!

We have this same problem with int-to-double, where hoisting a normal decimal integer literal out can change it from a double to an int. But we have good evidence that users have the right intuition about how that behaves, and there is a lot of prior art in other languages that inform that intuition.

I don't think a similar intuition exists for scientific notation. Given how rarely this feature is used, I don't think adding special case inference rules would carry their weight.

@mraleph
Copy link
Member

mraleph commented Apr 15, 2020

Given that both @lrhn and @munificent are not in support for this feature should this be closed as not planned?

@eernstg
Copy link
Member

eernstg commented Apr 15, 2020

I would not object to closing it as not planned.

@mraleph mraleph added the state-rejected This will not be worked on label Apr 15, 2020
@mraleph mraleph closed this as completed Apr 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems state-rejected This will not be worked on
Projects
None yet
Development

No branches or pull requests

6 participants