An array destructing specification choice

Allen Wirfs-Brock allen at
Mon Nov 7 08:49:07 PST 2011

On Nov 6, 2011, at 9:13 PM, Brendan Eich wrote:

> On Nov 6, 2011, at 11:18 AM, Allen Wirfs-Brock wrote:
>> On Nov 6, 2011, at 3:53 AM, Till Schneidereit wrote:
>>>> ...
>>> After thinking about this some more, I think I'd be fine with the
>>> above outcome after all. It seems to me as though the array
>>> destructuring pattern really only uses the syntax of arrays, not
>>> necessarily their semantics. Once row capture comes into play, not
>>> even the syntax matches completely, anymore.
>> I'm skeptical of ES every supporting row capture.  It is essentially an shallow copy (with exclusions) operation and it brings into to play all the copy semantics issues that up to this point we have been unwilling to try to take on.
> We have JS code such as Prototype's Object.extend that do for-in loops copying (own and inherited) enumerable properties from src to dest. It's not a problem.
> Why wouldn't row capture work similarly? Perhaps only own enumerable properties. Or all own properties, but the point is there's no deep clone complexity.

If you believe that there is complexity in cloning objects (and you have in other threads) then this seems like essentially the same clone operation but with some properties properties excluded.  

In other words,

   let {x, ...nobj} = obj;

seems equivalent to 

   let {x} = obj;
   let nobj = obj.cloneExcluding("x");

What is the [[Prototype]] of nobj;
Does it get any non-default internal properties of obj.
Are private named properties copied?
Are any internal invariants maintained or reestablished?
What if obj is a Proxy or hsot object?

>>> The important difference is that, as opposed to the slice example
>>> above, at no point during array destructuring an array object is
>>> created or modified.
>> Well, a (real) array object is created is a rest pattern is used.
> Why?

let [...restObj] = obj;

restObj is a real Array object.

>>> Given that, isn't the array destructuring pattern
>>> really a convenient way of saying "in this destructuring, all keys are
>>> numeric indices, starting at 0 and increasing linearly by 1"? I.e.,
>>> it's mostly syntax for another form of shorthand, pretty similar to
>>> {x} = {x:1}.
>> or does the use of the [ ] pattern also imply some deeper user intent about applying array-like semantics. 
> Not in our experience, or Opera's, or Rhino's.
> Maybe this is an edge case and I should quit beefing. However I do not like the aesthetics or the economics of a spec that gets 'length' for all array patterns, even if not needed.

i think it is an edge case and Opera/FF doesn't have rest destructuring which is where the issues are most apparent.  Given both of these points I not sure how informative the previous experience is.

As an edge case, I'm just trying to ensure that edge behavior is generally consistent across the language so people can reason about such cases without have to know and apply arbitrarily different rules in each such situation.  This is where I think the general behavior of arrays and array functions pretty directly tells us what the edge case behavior should be.

I actually think that [no, yes] is the closest to actual Array behavior.  Eg:

let  weirdArray = Array.prototype <| {3: 3} <| [0,1,2;

let a=weirdArray[0], b=weirdArray[2], r = weirdArray.slice(2); //a=01,b==2,r==[3]
let c = weirdArray[3];  //c==3   array [ ] access doesn't check the length...

We could make destructuring work this way

>> For [no, no] to implement ... we have to assume that the iteration limit is the max possible array index (currently Uint32 max - 1,
> No. We only need look at the properties that are actually present. I think you are dismissing row capture in object patterns and therefore focusing too narrowly on the "array" word in array patterns. If we want row capture in both, it will entail enumeration of actual properties, not wild integer counting till 2^32 or 2^53.

I actually addressed this in the rest of the paragraph this quote comes from.  Of course, you would only look at the actual properties  but you have to select out the array-indexed properties and order them appropriately.  This is significantly complicated by property inheritance. The bottom line is that what seemingly should be a simple and cheap destructuring such as:

let  [a,] = sup <| [0,1];   //should we just have to iterate from 1 to 1 to create rest

can be arbitrarily complex depending upon the shape of sup.  Even if it or its ancestors doesn't define any array indexed properties that still needs to be checked for. You don't even need to have the sup <| in order to have the issue because Array.prototype and Object.prototype can contribute array index properties that lay beyond the length bound.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list