Name: proposal-numeric-separator
Owner: Ecma TC39
Description: A proposal to add numeric literal separators in Javascript. https://tc39.github.io/proposal-numeric-separator/
Created: 2017-04-18 16:55:19.0
Updated: 2018-05-23 20:45:38.0
Pushed: 2018-04-09 17:33:59.0
Size: 124
Language: HTML
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
NOTE: We have found a potential conflict with a potential future feature here and we are presenting a plan in May. In the meantime, we ask implementations to hold before we get more validation. We'll update this section here as soon as we get a closure.
This is a proposal, the result of a merge between an earlier draft of itself and Christophe Porteneuve's proposal-numeric-underscores, to extend the existing NumericLiteral to allow a separator character between digits.
This feature enables developers to make their numeric literals more readable by creating a visual separation between groups of digits. Large numeric literals are difficult for the human eye to parse quickly, especially when there are long digit repetitions. This impairs both the ability to get the correct value / order of magnitude…
000000 // Is this a billion? a hundred millions? Ten millions?
75938.38 // what scale is this? what power of 10?
…but also fails to convey some use-case information, such as fixed-point arithmetic using integers. For instance, financial computations often work in 4- to 6-digit fixed-point arithmetics, but even storing amounts as cents is not immediately obvious without separators in literals:
t FEE = 12300;
s this 12,300? Or 123, because it's in cents?
t AMOUNT = 1234500;
s this 1,234,500? Or cents, hence 12,345? Or financial, 4-fixed 123.45?
Using underscores (_
, U+005F) as separators helps improve readability for numeric literals, both integers and floating-point (and in JS, it's all floating-point anyway):
0_000_000 // Ah, so a billion
475_938.38 // And this is hundreds of millions
fee = 123_00; // $123 (12300 cents, apparently)
fee = 12_300; // $12,300 (woah, that fee!)
amount = 12345_00; // 12,345 (1234500 cents, apparently)
amount = 123_4500; // 123.45 (4-fixed financial)
amount = 1_234_500; // 1,234,500
Also, this works on the fractional and exponent parts, too:
0_001 // 1 millionth
_000 // 10^10000 -- granted, far less useful / in-range...
(The following examples also appear in the README.md of Babel transform plugin for this proposal.)
budget = 1_000_000_000_000;
hat is the value of `budget`? It's 1 trillion!
et's confirm:
ole.log(budget === 10 ** 12); // true
nibbles = 0b1010_0001_1000_0101;
s bit 7 on? It sure is!
b1010_0001_1000_0101
^
e can double check:
ole.log(!!(nibbles & (1 << 7))); // true
essages are sent as 24 bit values, but should be
reated as 3 distinct bytes:
message = 0xA0_B0_C0;
hat's the value of the upper most byte? It's A0, or 160.
e can confirm that:
a = (message >> 16) & 0xFF;
ole.log(a.toString(16), a); // a0, 160
hat's the value of the middle byte? It's B0, or 176.
et's just make sure...
b = (message >> 8) & 0xFF;
ole.log(b.toString(16), b); // b0, 176
hat's the value of the lower most byte? It's C0, or 192.
gain, let's prove that:
c = message & 0xFF;
ole.log(c.toString(16), b); // c0, 192
hand wave emoji
Octals are great for permissions, but also look better when represented in 0o0000
form. No real benefit with separators here.
You can see what the specification design looks like here and a more detailed version here.
Our strawnman strategy is to start with a more restrictive rule (i.e. disallow both idioms) and losen it upon later if needed (as opposed to starting more broadly and worrying about backwards compatibility trying to tighten it up later).
In addition to that, we couldn't find good/practical evicence where (a) multiple consecutive underscores or (b) underscores before/after numbers are used effectively, so we chose to leave that addition to a later stage if needed/desired.
The _
was agreed to as part of Stage 1 acceptance.
The following examples show numeric separators as they appear in other programming languages:
_
(Java, Python, Perl, Ruby, Rust, Julia, Ada, C#)'
(C++)This proposal was developed by @samuelgoto, @ajklein, @domenic, @rwaldron and @tdd.
run build
t pi = 3.14_15F;
hexBytes = 0xFF_EC_DE_5E;
hexWords = 0xCAFE_F00D;
maxLong = 0x7fff_ffff_ffff_ffffL;
nybbles = 0b0010_0101;
bytes = 0b11010010_01101001_10010100_10010010;
Note that the first two examples are actually unlikely to be correct in any circumstance.
Trade-offs:
t pi1 = 3_.1415F; // Invalid; cannot put underscores adjacent to a decimal point
t pi2 = 3._1415F; // Invalid; cannot put underscores adjacent to a decimal point
x1 = _52; // This is an identifier, not a numeric literal
x2 = 5_2; // OK (decimal literal)
x3 = 52_; // Invalid; cannot put underscores at the end of a literal
x4 = 5_______2; // OK (decimal literal)
x5 = 0_x52; // Invalid; cannot put underscores in the 0x radix prefix
x6 = 0x_52; // Invalid; cannot put underscores at the beginning of a number
x7 = 0x5_2; // OK (hexadecimal literal)
x8 = 0x52_; // Invalid; cannot put underscores at the end of a number
x9 = 0_52; // OK (octal literal)
x10 = 05_2; // OK (octal literal)
x11 = 052_; // Invalid; cannot put underscores at the end of a number
'
).m = 36'000'000 // digit separators make large values more readable
m = 36_000_000 // Underscores (_) are allowed between digits for readability
Perl: multiple, anywhere
4_15_92 # a very important number
94_967_296 # underscore for legibility
f # hex
ead_beef # more hex
Ruby: single, only between digits.
4
Rust: multiple, anywhere.
11_1111_1001_0000_i32; // type i32
4.0E+18f64
Julia: single, only between digits.
a> 10_000, 0.000_000_005, 0xdead_beef, 0b1011_0010
00,5.0e-9,0xdeadbeef,0xb2)
456
159_26
otlin](https://kotlinlang.org/docs/reference/basic-types.html#underscores-in-numeric-literals-since-11)
val oneMillion = 1_000_000 val creditCardNumber = 1234_5678_9012_3456L val socialSecurityNumber = 999_99_9999L val hexBytes = 0xFF_EC_DE_5E val bytes = 0b11010010_01101001_10010100_10010010
Ongoing Proposals
ython Proposal: Underscore in Numeric Literals](https://www.python.org/dev/peps/pep-0515/#id19): single, only between digits.
amount = 10_000_000.0
addr = 0xCAFE_F00D
flags = 0b_0011_1111_0100_1110
flags = int('0b_1111_0000', 2)
# Proposal: Digit Separators](https://github.com/dotnet/roslyn/issues/216): multiple, only between digits.
int bin = 0b1001_1010_0001_0100; int hex = 0x1b_a0_44_fe; int dec = 33_554_432; int weird = 1_2345678_9; double real = 1_000.111_1e-1_000;
Related Work
ormat Specifier For Thousands Separator](https://www.python.org/dev/peps/pep-0378/)