tc39 / proposal-iterator.range

A proposal for ECMAScript to add a built-in Iterator.range()
https://tc39.es/proposal-iterator.range/
MIT License
487 stars 13 forks source link

Split the proposal into two proposals #57

Closed hax closed 1 year ago

hax commented 2 years ago

As previous discussions shown, the delegates (and the community) have disagreements of whether range() should be reusable iterable (like python or most programming languages) or one-shot iterator (seems already meet the common use case). This problem is the main factor that the proposal can not advance.

To break the ice, I think we'd better split the proposal into two possible alternative proposals (just like we did on pipeline proposals before).

One is iterable or even tuple-like range with possible features like includes, slice or subrange (return another range ).

One is much simpler iterator, only focus on iterating integers or just indexes (it's rare and always have precision-related issue to iterating floats, so many programming languages do not support iterating floats in the core lib).

Actually they can coexist if we finally found they satisfy different use cases well (I think so).

Featured iterable API

As tuple proposal is developed, I suppose range could be tuple-liked. Strictly, it should be named as "progression" or "stride", "range" normally mean "interval".

let r = Number.interval({start: 0, endInclusive: 1)
let p = r.progression({step: 0.25})
p.length: 5
p[2] // 0.5
p.includes(0.3) // false
let a = [...p] // [0, 0.25, 0.5, 0.75, 1]

// maybe progression could be treat as tuple with fast path, but no semantic diff?
p == #[0, 0.25, 0.5, 0.75, 1] // true?

Simplified iterator-only API

Iterator.indices = function *(start = 0, end = Number.MAX_SAFE_INTEGER - 1) { ... }

All args must be a valid "integer index" , or throw RangeError (like new Array(len)).

This is the simplest and strictest api, and follow Iterator.prototype.indexed() name.

If we think it's too limited, we could also consider:

Iterator.integers = function *(start, end, step) {
  if (typeof start == 'bigint') {
    // ensure end/step are also bigints...
    // do iteration 
  } else {
    // coerce the args to numbers, if not safe integers , throw RangeError/TypeError
    // do iteration 
  }
}

Another possibility is just overload Iterator.from to accept range-like object Iterator.from({start, end, step}).

tabatkins commented 2 years ago

It is definitely the case that an attempt at something interval-like should be a separate proposal. It's a completely different idea with totally separate use-cases.

There's no reason to "simplify" the current proposal, tho. Having a step, working with bigints and floats, and having an inclusive/exclusive choice are all reasoanble and simple things for a numeric iterator to do, and are already in the proposed draft spec.

Jack-Works commented 1 year ago

finally, we got to stage 2! no need to do the proposed splitting