1 of 22

Updates for range proposal

July 2020 / Jack Works

2 of 22

What’s new since Stage 1

  • Term changed “from” => “start”, “to” => “end”
  • Options bag as 3rd parameter
  • Add getters on %RangeIteratorPrototype%
  • New runtime behaviors
  • Tests

3 of 22

Options bag as 3rd parameter (PR)

// Initial design

Number.range(0, 5, 10)

// Now

Number.range(0, 5, 10)

Number.range(0, 5, { step: 10 })

// New inclusive option, 0, 1, 2, 3, 4, 5

[...Number.range(0, 5, { inclusive: true })]

4 of 22

New getters on %RangeIteratorPrototype% (PR)

const x = Number.range(0, 5, 10)

x.start // 0

x.end // 5

x.step // 10

x.inclusive // false

5 of 22

New runtime behaviors

// Allow BigInt range to Infinity

for (const x of BigInt.range(0n, Infinity))

if (x > 100n) break

// Allow step === 0, when start === end

Number.range(0, 0, 0) // Old: throw RangeError cause step is 0

//New: Emit nothing

// Infer step direction (1 or -1) when not specified

Number.range(0, 5).step === 1

Number.range(0, -5).step === -1

Number.range(0, -5, 1).step === 1

6 of 22

Semantics decisions

// Choose Yield-No-Value semantics for direction mismatch

[...Number.range(0, -5, 1)] // to be []

  • Precision lost (1e-324 + 1e-324) === (1e-324) behavior (Link)

No need to change.

  • Precision lost (Number.MAX_VALUE + 20 === Number.MAX_VALUE) behavior (Link)

No need to change.

  • Need Consensus: Iterable vs Iterator (Link)

Current: Iterator.

  • Need Consensus: Class vs plain function (Link)

Current: The latter.

7 of 22

Need Consensus: Iterator or Iterable(of something)

Iterator

Iterable

Consistency

with matchAll

with Array, Map, Set, ...

Diffuseness (with Iter Helper)

✅ range(...).map(...)

❌ range(...).values().map(...)

Closeness of Mapping

✅ it should be iterator naturally

❌ not very nature

Error Proneness (Re-usable #17)

() => range(...)

✅ range(...)

Hard Mental Operations

❌ Remember it’s not re-usable

✅ Nothing

8 of 22

Need Consensus: Plain function or Class?

Plain function

Class

Visibility / Diffuseness

✅ Number.range(...)

new Number.Range(...)

Maybe make it callable like Array?

Consistency

?

with all built-in Classes

Closeness of Mapping

❌ Behave like a class but construct like a normal function.

(Note: has a prototype, methods on the prototype and brand check)

✅ Behave like a class so let it become a class.

9 of 22

Add test to the spec complaint polyfill

Add tests to make sure no regressions introduced.

The polyfill is implemented the spec step-by-step and updated with the spec for any editorial or normative change.

Therefore it can used to test if the spec is doing strange things.

// Not test262 style but Jest.js style

https://github.com/tc39/proposal-Number.range/blob/master/__tests__/test.js

10 of 22

Next step

  1. Spec text rewrite with “CreateIteratorFromClosure”
    1. depends on pull #2045: Editorial: Add Yield, CreateIteratorFromClosure, CreateAsyncIteratorFromClosure abs op.
  2. Discover more possible options.
  3. Question: should range(n) means range(0, n)?
  4. Discover more possible helper functions on %RangeIteratorPrototype%.
  5. If we get consensus that semantics needs to change, change it.

11 of 22

Stage 2?

  • [✔] Spec text https://tc39.es/proposal-Number.range/
  • [✔] Implementation (Playground)
  • [🤔] all major semantics, syntax and API are covered
    • Hope we got consensus from the previous discussions.

12 of 22

await.operations proposal

July 2020 / Champion: Jack Works, Jordan Harband

Repo / Spec / Playground

13 of 22

TL;DR; Extends the definition of AwaitExpression

await.all expr

// eq: await Promise.all(expr)

await.race expr

// eq: await Promise.race(expr)

await.allSettled expr

// eq: await Promise.allSettled(expr)

await.any expr

// eq: await Promise.any(expr)

14 of 22

Motivation & Usage

// before

await Promise.all(users.map(async x => fetchProfile(x.id)))

// after

await.all users.map(async x => fetchProfile(x.id))

Motivation: See discussion at Allow "awaiting" on arrays - 💡 Ideas

15 of 22

Possiblility to extend for await of syntax (#9)

(Not intent to add it in this proposal)

for await.all(const x of iterable) {

console.log(x)

}

// Loosely equals to: (despite break/continue/return/...)

await Promise.all([...iterable].map(async x => {

console.log(x)

})

16 of 22

Problems

  • It's a bit strange to have an uppercase letter (await.allSettled) in an operator (#5)
  • Syntax ambiguity in top-level await (#7)
    • await.all [x]
    • variable.property [index]
  • “await” on Arrays is commonly required, but does it worth to add new syntax?

17 of 22

await.all delegates;

try {

advance_stage(1);

} catch {}

18 of 22

Array.prototype.unique

July 2020 / Champion: Jack Works / Author: TechQuery

Repo / Polyfill on npm

19 of 22

Motivation

Deduplication is one of the most common requirements in Data processing, especially in large Web Apps nowadays.

[...new Set(array)] in ECMAScript 6 isn't enough for Non-primitive values, and now, we may need a Array.prototype.unique().

20 of 22

API design

arr.unique()

// eq [...new Set(arr)] or …?

arr.unique("key")

arr.unique(1)

arr.unique(Symbol.for("key"))

// deduplicate by each_item[key]

arr.unique(x => x.toJSON())

// deduplicate by the provided function

21 of 22

Problems

  • Does it break the Web? (like flatten)
  • Should we keep the arr.unique("key") style API? (Inconsistent API style)

22 of 22

Stage 1?