Array tail destructuring

Tab Atkins Jr. jackalmage at gmail.com
Tue Oct 4 17:55:40 UTC 2016


On Mon, Oct 3, 2016 at 8:06 PM, Caitlin Potter <caitpotter88 at gmail.com> wrote:
>> On Oct 3, 2016, at 10:54 PM, Tab Atkins Jr. <jackalmage at gmail.com> wrote:
>>> On Sun, Oct 2, 2016 at 2:11 AM, Caitlin Potter <caitpotter88 at gmail.com> wrote:
>>>> On Oct 2, 2016, at 10:50 AM, Awal Garg <awalgarg at gmail.com> wrote:
>>>>> On Oct 2, 2016, at 9:30 AM, Olivier Lalonde <olalonde at gmail.com> wrote:
>>>>> So what's the problem with `[...a, last]` that `[...a]` doesn't have? I
>>>>> still don't get it.
>>>>
>>>> Since you don’t know when the iterator produced for `…a` will terminate,
>>>> there’s no way to know when you need to stop iterating `…a` and move onto
>>>> the next item `last`.
>>>
>>> That statement is factually incorrect. There is a simple criteria to know
>>> when to terminate the iteration for a final rest element, which is when the
>>> iterator returns a result object with "done": true.
>>>
>>> There is no condition to determine when to switch from a non-final rest
>>> element to some other element. That is a problem which needs to be
>>> addressed.
>>
>> I'm similarly confused - there's no need to "determine when to
>> switch"; we don't evaluate things in different contexts or anything.
>> It just requires storage equal to the number of post-rest arguments;
>> when you do hit the end, the things you're holding onto get assigned
>> to the post-rest variable names.  This is all done internally with a
>> freshly-produced array; I don't *think* the timing of array-appending
>> is even observable, so you shouldn't be able to tell that an item is
>> appended only after later items are pulled from the source iterator.
>>
>> I'm similarly confused by the wording you're using, tho, which
>> suggests there may be a deeper communication mismatch - there's no
>> "iterator produced for `...a`".  The ...a just indicates that you need
>> to pull on the iterator being assigned to the destructuring pattern,
>> and store the results that aren't claimed by other parts of the
>> destructuring pattern into "a".
>
> "I'm similarly confused about your assertion that this idea needs to avoid a halting problem, because here's a way around this problem, not suggested by anyone else, with a non-negligible cost, so there"?
>
> Really? I'm asking how they would alter IteratorBindingInitialization. It's not rocket science, but it's important for the discussion.

Right, the details are important, but there's clearly no need to
predict future behavior to achieve it; you can do this sort of thing
in userland already.

> Also, this behaviour differs observably from the current behaviour, I believe. Consider:
>
> ```
> try {
>   var [...x, y, z] = <object where retrieving the last element throws>
> } catch (e) {
>   console.log(y); // initialized?
> }
> ```
>
> I'm fairly sure currently (ignoring the non-final rest element) everything would be bound except for `z`. But in this idea, it sounds like it wouldn't be.
>
> So, another thing to deal with, I guess

Ah, yes, so it is observable, good catch.  Yes, the only reasonable
way to do this is to have an N-element delay in assigning, where N is
the number of post-rest arguments, and then only assign the final N
arguments when the end of the iterator is hit.  So in this case, both
y and z would be uninitialized; the algo would be holding onto one
pending element (to be assigned to y if the next pull returns a
{done:true}) and the throw prevents it from doing that assignment.

~TJ


More information about the es-discuss mailing list