tj.crowder at farsightsoftware.com (2017-08-03T14:46:46.298Z)
On Thu, Aug 3, 2017 at 10:18 AM, James Browning
<thejamesernator at gmail.com> wrote:
>
> The 1, 1 would happen if you decided that `[a, ...rest, b]` read
> in both directions (although personally I'm not a fan of this
> approach)...
Gotcha. Yeah, having it duplicate things would seem wrong. :-)
> One option could be (although I don't like it either) to allow
> the rest operator to have a direction...
I'd say: Keep it simple. Left-to-right, non-duplicating, non-greedy with
respect to non-rest bindings, greedy otherwise:
```js
function *source(len) {
for (let n = 1; n <= len; ++n) {
yield n;
}
}
function test(len) {
const [ a, ...rest, b, c ] = source(len);
console.log("With " + len + ":", a, rest, b, c);
}
test(0); // With 0: undefined, [], undefined, undefined
test(1); // With 1: 1, [], undefined, undefined
test(2); // With 2: 1, [], 2, undefined
test(3); // With 3: 1, [], 2, 3
test(4); // With 4: 1, [2], 3, 4
test(5); // With 5: 1, [2, 3], 4, 5
```
On Thu, Aug 3, 2017 at 10:29 AM, Andy Earnshaw
<andyearnshaw at gmail.com> wrote:
>
> If you think of rest as "everything else" (which is what it already is)
> then this feels pretty natural and is easy to reason about.
Exactly. (And as you say, hardly original with me.)
A pragmatic approach could simply consume the rest of the iterable into the
rest binding and then if there are more bindings after it, move those
entries into them:
```js
function assignToBindings(bindings, iterator) {
let bindingIndex = 0;
let currentBinding;
let e;
// Consume bindings prior to rest
while ((currentBinding = bindings[bindingIndex++]) && !currentBinding.isRest) {
e = iterator.next();
if (e.done) {
return;
}
currentBinding.value = e.value;
}
if (!currentBinding) {
return; // Out of bindings
}
// Read to the end into the rest binding
assert(currentBinding.isRest, "hit rest binding");
const rest = currentBinding.value;
while (!(e = iterator.next()).done) {
rest.push(e.value);
}
if (bindingIndex >= bindings.length) {
return; // rest binding was last binding
}
// Move trailing entries out of the rest binding into the trailing bindings
const restLength = Math.max(0, rest.length - (bindings.length - bindingIndex));
for (let restIndex = restLength; restIndex < rest.length; ++restIndex) {
bindings[bindingIndex++].value = rest[restIndex];
}
rest.length = restLength;
}
```
[Fiddle with examples/tests](https://jsfiddle.net/p35vt5yc/).
-- T.J. Crowder
On Thu, Aug 3, 2017 at 10:18 AM, James Browning <thejamesernator at gmail.com> wrote: > > The 1, 1 would happen if you decided that `[a, ...rest, b]` read > in both directions (although personally I'm not a fan of this > approach)... Gotcha. Yeah, having it duplicate things would seem wrong. :-) > One option could be (although I don't like it either) to allow > the rest operator to have a direction... I'd say: Keep it simple. Left-to-right, non-duplicating, non-greedy with respect to non-rest bindings, greedy otherwise: ```js function *source(len) { for (let n = 1; n <= len; ++n) { yield n; } } function test(len) { const [ a, ...rest, b, c ] = source(len); console.log("With " + len + ":", a, rest, b, c); } test(0); // With 0: undefined, [], undefined, undefined test(1); // With 1: 1, [], undefined, undefined test(2); // With 2: 1, [], 2, undefined test(3); // With 3: 1, [], 2, 3 test(4); // With 4: 1, [2], 3, 4 test(5); // With 5: 1, [2, 3], 4, 5 ``` On Thu, Aug 3, 2017 at 10:29 AM, Andy Earnshaw <andyearnshaw at gmail.com> wrote: > > If you think of rest as "everything else" (which is what it already is) then this feels pretty natural and is easy to reason about. Exactly. (And as you say, hardly original with me.) A pragmatic approach could simply consume the rest of the iterable into the rest binding and then if there are more bindings after it, move those entries into them: ```js function assignToBindings(bindings, iterator) { let bindingIndex = 0; let currentBinding; let e; // Consume bindings prior to rest while ((currentBinding = bindings[bindingIndex++]) && !currentBinding.isRest) { e = iterator.next(); if (e.done) { return; } currentBinding.value = e.value; } if (!currentBinding) { return; // Out of bindings } // Read to the end into the rest binding assert(currentBinding.isRest, "hit rest binding"); const rest = currentBinding.value; while (!(e = iterator.next()).done) { rest.push(e.value); } if (bindingIndex >= bindings.length) { return; // rest binding was last binding } // Move trailing entries out of the rest binding into the trailing bindings const restLength = Math.max(0, rest.length - (bindings.length - bindingIndex)); for (let restIndex = restLength; restIndex < rest.length; ++restIndex) { bindings[bindingIndex++].value = rest[restIndex]; } rest.length = restLength; } ``` [Fiddle with examples/tests](https://jsfiddle.net/p35vt5yc/). -- T.J. Crowder -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170803/4fdbf744/attachment.html>