An array destructing specification choice

Allen Wirfs-Brock allen at wirfs-brock.com
Mon Nov 14 09:49:03 PST 2011


On Nov 12, 2011, at 12:02 PM, Brendan Eich wrote:

> On Nov 12, 2011, at 2:07 AM, Axel Rauschmayer wrote:
> 
>>> Embedded spreads is already in the ES6 draft for  both array literals and argument lists.  I'm not at all sure that embedded rests in destructurings are such a good idea.
>> 
>> I think it would be nice to express “last element(s)", e.g. in function parameters (where the callback is usually at the end):
>> 
>>     foo(arg1, arg2, ..., argn, callback)
> 
> Yes.
> 

aside from the "what does it mean" issue (more below) there is still the issue that I believe implementations will continue to prefer to have statically assignable stack offsets for formal parameters. Eg in pseudo assembly language (with infinite registers), you would normally access the parameters of function(arg1,arg2,...rest) something like:

    load Rp,(framePointer)+arg1Offset  //load value of arg1
    load Rq,(framePointer)+arg2Offset  //load value of arg2
    load Rr(framePointer)-restLocalOffset  //rest is a local var probably pointing to a array, initialized by function prolog or maybe some other optimization


allowing non-trailing rest parameters forces something more like:
parameters of function(arg1,...rest, arg2,arg3) something like:

    load Rp,(framePointer)+arg1Offset  //load value of arg1
    load Rr(framePointer)-restLocalOffset  //rest is a local var, initialized by function prolog or maybe some other optimization
   // next 3 instructions required to access value of arg2
    load Rx, (framePointer)+argCountOffset //get length of actual arg list
    lea   Ry,(framePoint,Rx)+arg1Offset  //computer address of last argument
    load Rq,(Ry)-arg2ReverseOffset  //load value of arg2

It's doable, but an additional implementation complication with a runtime cost

> 
>>> Just to start with, what does this mean:
>>> 
>>>  [a,b,...r,c,d = [1,2,3]
>> 
>> That seems related to
>>     [a, b, c, d] = [1,2,3]
>> and to
>>     [a,b,...r,c,d] = [1,2,3,4]
>> 
>> Hence, I would guess:
>> a === 1
>> b === 2
>> r === []
>> c === 3
>> d === undefined
> 
> Why guess? There is no requirement that ...r consume 1 element, but there is a requirement in Dave's desugaring that trailing non-rest element patterns consume elements up to the one indexed by rhs.length - 1.

I originally said "If it isn't obvious what it means it probably should be in the language."

Guessing comes into play when there are multiple reasonable interpretations and one has been "arbitrarily" chosen by the language designers.   As a new user of the feature or even just a infrequent user I can't reliably reason out what it means, I have to learn and remember the language designer's choice.  

If rests only come at the end, then it is easy to learn, remember, or even reason out what it means.

If rests come in the middle, I have to know "Dave's Algorithm" to understand what the code means.  There are other reasonable algorithms so if I don't specifically remember Dave's I have to "guess".  I might guess wrong.

It isn't obvious to me, that the additional language complexity carries it weight in utility. Trailing rests are easy to understand and undoubtably the most frequent use case.  leading rests are also fairly easy to understand (put note the formal parameter impl issue) and are probably the next most common.  Interior rests makes things complicated and have even fewer uses.



Allen


More information about the es-discuss mailing list