tc39/proposal-numeric-separator

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

Homepage:

Size: 124

Language: HTML

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

Numeric Separators

Stage 3

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.

Motivation

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...
Examples

(The following examples also appear in the README.md of Babel transform plugin for this proposal.)

Decimal Literals
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
Binary Literals
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
Hex Literal
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
Octal Literal

hand wave emoji

Octals are great for permissions, but also look better when represented in 0o0000 form. No real benefit with separators here.

Specification

You can see what the specification design looks like here and a more detailed version here.

Background
Alternative Syntax

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.

Character

The _ was agreed to as part of Stage 1 acceptance.

The following examples show numeric separators as they appear in other programming languages:

Acknowledgements

This proposal was developed by @samuelgoto, @ajklein, @domenic, @rwaldron and @tdd.

Building the spec:
run build
References
Prior art
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  
4_15_92          # a very important number
94_967_296       # underscore for legibility
f                # hex
ead_beef         # more hex
a> 10_000, 0.000_000_005, 0xdead_beef, 0b1011_0010
00,5.0e-9,0xdeadbeef,0xb2)
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.

grouping decimal numbers by thousands

amount = 10_000_000.0

grouping hexadecimal addresses by words

addr = 0xCAFE_F00D

grouping bits into nibbles in a binary literal

flags = 0b_0011_1111_0100_1110

same, for string conversions

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/)

This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.