tc39 / proposal-slice-notation

http://tc39.es/proposal-slice-notation/
MIT License
526 stars 19 forks source link

Impact of negative step on inclusivity/exclusivity and default values #29

Closed nlepage closed 4 years ago

nlepage commented 5 years ago

Hi,

Inclusivity/exclusivity and default values of the bounds are consistent with Array.prototype.slice, which is a good thing in my opinion, and their characteristics could be summarized like this:

But Array.prototype.slice has no step argument, so what happens to the inclusivity/exclusivity and default values of the bounds when the step is negative?

All we know is this:

const arr = ['a', 'b', 'c', 'd'];

arr[::-1];
// → ['d', 'c', 'b', 'a']

If we keep the terms lower and upper bounds (meaning lower bound is inferior to upper bound), this could mean two things:

Python changes the inclusivity/exclusivity of the bounds (here upper bound 2 is inclusive and lower bound 0 is exclusive):

arr = ["a", "b", "c", "d"];
arr[2:0:-1];
// → ['c', 'b']

I think sticking with python is a good idea.

Either way, this should be documented, and have at least one example.

Finally, I think using "lower" and "upper" to refer to the bounds is a little bit confusing (at least to me), because when using a negative step the bounds change places, the upper bound comes first and the lower bound comes second.

"start" and "end" would have been more understandable to me, but maybe it is just a personal vue...

Thx for your work.

caub commented 5 years ago

You wrote arr[2:0:-1], are you sure you didn't mean arr[0:2:-1]?

currently I think this proposal says that arr[2:0:step] will be [] whatever the value of step, this is the same behavior than .slice

and it seems to say that arr[start:end:-1] is arr[start:end][::-1] (so arr[start:end] reversed), where indeed the end index (the starting index in the resulting array) is exclusive, but I think it's consistent

nlepage commented 5 years ago

Hi @caub

Yes I'm sure I meant arr[2:0:-1], in Python arr[0:2:-1] gives [].

To me, the proposal is not so accurate about the step as you seem to think :

However the proposal does say it "is highly inspired by Python".

Anyway, that's why I was priorily saying that this should be documented, because this is clearly open to different interpretations.

My personal opinion is it should stick with Python :slightly_smiling_face:

caub commented 5 years ago

I meant .slice behavior for non-integers, like it would floor 1.5 (as a step or start or end), .. but overall you're totally right, this proposal is still too vague

I'm fine with the upper-bound inclusive if step<0, it's actually easier to implement

arr[0:2:-1] equals [arr[2], arr[1]]

function* (si, ei, step) {
  if (step<0){
    for (let i = ei; i > si; i += step) yield arr[i];
  }else{
    for (let i = si; i < ei; i += step) yield arr[i];
  }
}

Versus this for arr[0:2:-1] equals [arr[1], arr[0]]

function* (si, ei, step) {
  if (step<0){
    for (let i = ei-step; i >= si; i += step) yield arr[i];
  }else{
    for (let i = si; i < ei; i += step) yield arr[i];
  }
}
caub commented 5 years ago

Those are the 2 possible behaviors I can think of:

1. python

> [0,1,2,3,4,5,6,7][0:4]
[0, 1, 2, 3]
> [0,1,2,3,4,5,6,7][0:4:-1]
[]
> [0,1,2,3,4,5,6,7][4:0:1]
[]
> [0,1,2,3,4,5,6,7][4:0:-1]
[4, 3, 2, 1]

2.

> [0,1,2,3,4,5,6,7][0:4]
[0, 1, 2, 3]
> [0,1,2,3,4,5,6,7][0:4:-1]
[3, 2, 1, 0]
> [0,1,2,3,4,5,6,7][4:0:1]
[]
> [0,1,2,3,4,5,6,7][4:0:-1]
[]

I've the feeling the author of the proposal thought about 2. rather than 1., because 2. follows how .slice works (always return empty array when the endIndex is lower or equal startIndex) but I'm maybe wrong too

@gsathya could confirm