1 of 12

Extended numeric literals

Stage 1 update

Daniel Ehrenberg

Igalia

In partnership with Bloomberg

March 2018 TC39

2 of 12

Motivation: Generalize new numeric literals

  • Built-in:
    • 1236536253453n BigInt
  • Extended:
    • 4525_i Imaginary numbers
    • 235435.461_m User-defined Decimal
    • 300_px CSS Typed OM

3 of 12

Syntax

PrimaryExpression[Yield, Await] :� ...� ExtendedNumericLiteral��ExtendedNumericLiteral ::� NumericLiteral _ IdentifierPart

  • Suffix must start with _
  • No complex expressions allowed
  • No whitespace between Number and suffix
  • Numeric part uses Number grammar

4 of 12

Semantics

1234_i

_i(Object.freeze({string: "1234", number: 1234}))

  • Object is cached just like tagged templates
    • Use in WeakMap to avoid re-parsing work

5 of 12

Issue: Ambiguity with numeric separators

  • 0x123_abc
    • Is this a numeric separator or extended literal???
  • C++'s solution: 0x123’abc (for numeric separator)� 0x123_abc (for custom literal)
  • We are on track for _ for our numeric separator
  • …oops, what do we do?
  • This is kinda fatal. We need to figure out another syntax.

6 of 12

Issue: Ambiguity with numeric separators

  • Candidates to replace _ to lead extensible literal
    • __
    • $
    • Others?
  • Candidates to replace _ for numeric separator
    • -- C++’s solution
    • Intl.NumberFormat("de-CH").format(10000000000000)
    • "10’000’000’000’000"
    • Others?
  • Issue

7 of 12

Issue: Bikeshedding for prettiness

  • Is the underscore too ugly?
  • Are we ASCII soup yet?
  • Alternatives that resolve the ambiguity even worse?
  • Twitter thread

8 of 12

Status

  • Explainer
  • Spec text (but with the ambiguous syntax issue)
  • No implementations or tests
  • Currently Stage 1
  • Any thoughts on these issues?
  • Want to get more involved in this proposal?

9 of 12

Previously considered alternatives

10 of 12

Scoping details: Mangled?

function __literal_i() { ... }

import { __literal_i } from "literals.js";

1234i --> __literal_i("1234", 1234)

  • Downside: Ugly when it leaks

11 of 12

Scoping details: Namespace?

function literal i() { ... }

import { literal i } from "literals.js";

1234i --> [literal i]("1234", 1234)

  • Could work, but complexity

12 of 12

Scoping details: Object property?

Literals.i = function i() { ... }

import "literals.js"; // mutates Literals

1234i --> Literals.i("1234", 1234)

  • Global mutable object :(