Claude Pache (2014-02-18T20:32:40.000Z)
Le 17 févr. 2014 à 21:25, Brendan Eich <brendan at mozilla.com> a écrit :

> C. Scott Ananian wrote:
>> But as you point out, I don't think there's any actual behavior
>> change, since everything washes out to `0` at the end.  It's just a
>> matter of writing a clearer more consistent spec.
> 
> Yet in that light you still have a point, I think. Allen?
> 
> /be



Different perspectives... My point of view is precisely that, with the change proposed, the algorithm is less clear, and less consistent, for the reasons stated in this thread. The benefit of the change is that the signature `Array.prototype.copyWithin (target, start, end = this.length)` doesn't lie for silly values of `this`. Is it worth the added obscurity and inconsistency of the algorithm itself for these same cases?

But I think that clarity can be improved by avoiding to obscure the intent by computation details. For my personal polyfill, I have found useful to abstract out the following steps, used (with slight variations) thrice in `Array.prototype.copyWithin` and twice in `Array.prototype.fill`, (and which can be used for various other methods of `Array.prototype`):

IndexFromRelativeIndex(`k`, `len`, `default`)
---------------------------------------------

1. Assert: `len` is an integer between 0 and 2^53-1.
2. Assert: `default` is an integer between 0 and `len`.
3. If `k` is `undefined`, return `default`
4. Let `relative` be ToInteger(`k`). ReturnIfAbrupt(`relative`).
5. If `relative` >= 0, return min(`relative`, `len`).
6. Else, if `relative` < 0, return max(`len` + `relative`, 0). 

I think that the intent of this algorithm is clear despite its Cobol-like language. Actually, for step 3, the spec uses the equivalent of: "If `k` is `undefined`, let `relative` be `default` and go to step 5"; moreover, that step is omitted when `default` is 0. The places where `Array.prototype.copyWithin` [1] uses it, are (where `len = ToLength(this.length)` per step 4):

steps 6 to 8. Let `to` be IndexFromRelativeIndex(`target`, `len`, 0). ReturnIfAbrupt(`to`).  
steps 9 to 11: Let `from` be IndexFromRelativeIndex(`start`, `len`, 0). ReturnIfAbrupt(`from`).  
steps 12 to 14: Let `final` be IndexFromRelativeIndex(`end`, `len`, `len`). ReturnIfAbrupt(`final`).  

Note in particular that the default value is always one of the two ends of the range of possible positions, either 0 or `len`.

—Claude

[1] https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.copywithin


—Claude
domenic at domenicdenicola.com (2014-02-21T20:19:43.801Z)
Le 17 févr. 2014 à 21:25, Brendan Eich <brendan at mozilla.com> a écrit :

> Yet in that light you still have a point, I think. Allen?


Different perspectives... My point of view is precisely that, with the change proposed, the algorithm is less clear, and less consistent, for the reasons stated in this thread. The benefit of the change is that the signature `Array.prototype.copyWithin (target, start, end = this.length)` doesn't lie for silly values of `this`. Is it worth the added obscurity and inconsistency of the algorithm itself for these same cases?

But I think that clarity can be improved by avoiding to obscure the intent by computation details. For my personal polyfill, I have found useful to abstract out the following steps, used (with slight variations) thrice in `Array.prototype.copyWithin` and twice in `Array.prototype.fill`, (and which can be used for various other methods of `Array.prototype`):

IndexFromRelativeIndex(`k`, `len`, `default`)
---------------------------------------------

1. Assert: `len` is an integer between 0 and 2^53-1.
2. Assert: `default` is an integer between 0 and `len`.
3. If `k` is `undefined`, return `default`
4. Let `relative` be ToInteger(`k`). ReturnIfAbrupt(`relative`).
5. If `relative` >= 0, return min(`relative`, `len`).
6. Else, if `relative` < 0, return max(`len` + `relative`, 0). 

I think that the intent of this algorithm is clear despite its Cobol-like language. Actually, for step 3, the spec uses the equivalent of: "If `k` is `undefined`, let `relative` be `default` and go to step 5"; moreover, that step is omitted when `default` is 0. The places where `Array.prototype.copyWithin` [1] uses it, are (where `len = ToLength(this.length)` per step 4):

steps 6 to 8. Let `to` be IndexFromRelativeIndex(`target`, `len`, 0). ReturnIfAbrupt(`to`).  
steps 9 to 11: Let `from` be IndexFromRelativeIndex(`start`, `len`, 0). ReturnIfAbrupt(`from`).  
steps 12 to 14: Let `final` be IndexFromRelativeIndex(`end`, `len`, `len`). ReturnIfAbrupt(`final`).  

Note in particular that the default value is always one of the two ends of the range of possible positions, either 0 or `len`.

[1]: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.copywithin