tc39 / proposal-iterator.range

A proposal for ECMAScript to add a built-in Iterator.range()

Home Page:https://tc39.es/proposal-iterator.range/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

The `step` value: useful default and allowing zero in an empty range

Andrew-Cottrell opened this issue · comments

I have previously implemented an equivalent function and found it useful for the optional step parameter to default to Math.sign(to - from). This enables the expected result in

for (const number of Number.range(10, 5)) {
    console.log(number); // 10, 9, 8, 7, 6
}

The caller might compute the step argument using the from and to values, which may result in zero when from and to have the same value. The calling code is simplified if a zero step is allowed when from is exactly equal to to. Obviously the result is an empty range of numbers.

const from = <some finite number>;
const to = <same or different finite number>;

// preferable to allow zero step in an empty range
const range = Number.range(from, to, (to - from) / 10);

// otherwise need to remember to use an awkward guard
const range = Number.range(from, to, ((to - from) / 10) || 1);

The intuition is the step value should be irrelevant when there is no step to be taken.

That makes sense for me to allow 0 when from === to.

But "an empty range" is not clear. BigInt.range(0n, 1n)(sorry for my wrong example) is also an empty range. Should we allow step 0n on it?

In the previous discussion (#5), we decided to use yield no value semantic when the step direction is inequal to the from and to.

@tabatkins writes "it (ignoring the explicit step order) is actually too clever" so we won't overwrite direction of the explicit step. Now, if the step is implicit, should we infer the step order from from and to? I think it's a good idea, but I don't know if it is too clever again for others.

Or maybe we can add a new option for it when the developer wants to infer the step. Like:

range(0, 1) // infer
range(0, 1, 1) // no infer for explicit step
range(0, 1, { step: 1 }) // no infer for explicit step
range(0, 1, { step: 1, infer: true }) // explicit opt-in for direction infer
range(0, 1, { other_opts: whatever }) // infer

[deleted: unimportant aside replying to a question regarding an empty range]

In any case, my suggestion is to allow step === 0 or step === 0n exactly when from === to. The definition of an empty range doesn't change my suggestion.

In the previous discussion (#5), we decided to use yield no value semantic when the step direction is inequal to the from and to.

I certainly agree Number.range(8, 15, -1) should not return a range that yields a value. My implementation throws RangeError, but I have no disagreement with the yield no value semantic.

@tabatkins writes "[...] Now, if the step is implicit, should we infer the step order from from and to? I think it's a good idea, but I don't know if it is too clever again for others.

I think the idea is simple & obvious enough to be easily understood by ECMAScript developers across the spectrum of knowledge and experience. In fact, I think beginners would be surprised if Number.range(10, 5) did not yield a sequence 10, 9, 8, ....

Or maybe we can add a new option for it when the developer wants to infer the step.

I'd rather leave it alone than add a new option!

Sorry my example on BigInt is wrong.

Sorry my example on BigInt is wrong.

@Jack-Works, no worries; your knowledge of BigInt is clearly greater than mine regardless of the minor slip-up.

Yeah, I'm fine with an implicit step calculating its direction according to the endpoints. I do that in my own range() function. I too would find it surprising if range(10,5) didn't produce a decreasing list of numbers.

I'll note that this is not what Python does - list(range(10,5)) yields []. So I'd be fine either way, I just lean slightly towards "range(10,5) should return [10,9,8,7,6]".

I'm not sure whether infer step is a good idea, if python/ruby and other languages not choose this way. Maybe we should check and analysis other languages to see why they don't infer, and revisit this issue.