Hi Sean, I think you make a good case for hole preservation. However, holes in 
actual and formal parameter lists are not that wanted. You want them for 
consistency with holes in array pattern destructuring parameters. That's 
unusual, but I grant that if they're useful for destructuring, they could be 
useful for parameter lists too. In some languages, you would use a dummy name 
such as _.

The thing that gives me pause about extending the grammar for ArgumentList and 
FormalParameterList is the reports from Dean Landolt about "comma first" style 
users vs. "comma last" creating unintended holes in array literals. This is 
horrifying. It makes me abominate comma-first, but it also makes me want to be 
cautious about spreading holey syntax to parameter lists.

There are many kinds of consistencies to advance, along different dimensions. 
Some trade against others, directly or at an angle. Is this really worth the 
potential trouble?

/be

On Oct 5, 2011, at 12:19 PM, Sean Eagan wrote:

> On Mon, Oct 3, 2011 at 4:37 PM, Allen Wirfs-Brock <[email protected]> 
> wrote:
>> apply supports holes...
>> 
>> f.apply(Array(5));
>> 
>> Look at the specification of apply in section 15.3.4.3 of the ES5/5.1 spec.
>>  It does a [[Get]] on each element of the argArray to get the value that
>> passed in the argument list.  [[Get]] converts holes to undefined.
> 
> The only way this is observable in ES5 is if argArray has getters for
> any of the indexes between 0 and argArray.length.  I'm not aware of
> any cases of objects defining getters for indexed properties, much
> less those objects being passed to Function.prototype.apply.  So the
> only consequence of this is that the hole preservation algorithms in
> the draft spec only call [[Get]] when [[HasProperty]] returns true.
> So we could either tweak the hole preservation algorithm for rest
> parameters to call [[Get]] regardless, or the better option IMHO,
> match the other algorithms by no longer calling [[Get]] for holes in
> argArray, at least when Function.prototype.apply is called from
> extended code.
> 
>> 
>> syntactic calls will support holes...
>> 
>> f(...Array(5))
>> 
>> by syntactic calls I meant f(a,b,c).  the legacy language does not allow for
>> f(a,,c)
> 
> This can be said of any any syntax being added in ES.next.  Also, I'm
> only suggesting to add that syntax if it continues to be available in
> array literals.
> 
>> What *doesn't* support holes is the `arguments` object which is on its way
>> out.
>> 
>> In addition, the specification of the semantics of function invocation made
>> no allowance for the possibility of holes in an argument list.
>> 
>> The specification of `arguments` dictates this, not function
>> invocation as a whole.
>> 
>> Sorry that is incorrect, see 15.3.4.3
> 
> You are correct, sorry.  However, this is merely an unobservable
> specification detail, so what relevance does it have to what is best
> for the future of the language ?
> 
>> What about holes makes them applicable to arrays in general but not
>> argument arrays ?  Everything else in ES.next points to reification of
>> arguments as plain old arrays, why be different here ?
>> 
>> Because we aren't talking about reification of arguments.  We are talking
>> about the semantics of an argument list in a function call expression and
>> the semantics of the spread operator.
> 
> The spread operator in argument lists reifies the argument list as an
> array in my view.  But mostly I just care that the semantics are the
> same as when the spread oeprator occurs in an array literal, i.e. that
> holes are preserved for the receiver.  If a caller does not want holes
> to be observed by a potential callee rest argument, they can use a
> dense argument list, however I'm not sure why they would care about
> this.  If a caller *does* want to allow a potential callee rest
> parameter to utilize holes for optimization purposes, why prevent them
> from doing so?
> 
>> I would actually be ok with or without both Elision syntax and hole
>> preservation in ES.next, I just want consistency.
>> 
>> One concern that I've already mentioned is that recognizing holes in spread
>> would create an inconsistency with the existing semantics of apply and that
>> changing apply would be a breaking change that might impact existing code.
>> 
>> apply does not have existing semantics for rest parameters since they
>> don't yet exist, I'm not suggesting to change the semantics for
>> `arguments` while it's still around
>> 
>> Apply is on the caller side.  It doesn't have any parameter semantics at
>> all.  It is only responsible for passing on a valid argument list.
>> Because apply and normal function application can't depend knowledge to the
>> callee, it is reasonable to expect that:
>>    foo.apply(undefined,x)
>> means exactly the same thing as
>>    foo(...x)
>> 
> 
> Yes, I intend for them to mean the same thing, which is that holes in
> x which fall within a range covered by a rest parameter in foo are
> preserved.  If foo uses `arguments` they continue to show up as
> undefined values there.
> 
>> function f(arg) {
>>  [a='a', b='b'] = arg;
>> 
>> The above line is not legal syntax according to the current specification
>> draft.  The destructuring binding pattern and a destructuring assignment
>> pattern have both different syntax and semantics.
>> In a destructuring binding, a scalar BindingElement is defined as:
>>    SingleNameBinding : BindingIdentifier Initializer-opt
>> while in a destructuring assignment, a scalar AssignmentElement is defined
>> as
>>    AssignmentElement : LeftHandSideExpression
>> Note that an AssignmentElement does not have an Initializer.  The reason I
>> defined it this way is that unlike a BindingIdentifier, a
>> LeftHandSideExpression can be an arbitrary complex expression. I didn't want
>> to allow expressions such as:
>>    [new foo.bar[baz(x=5)].bam=0] = obj;
>> where the trailing initializer looks like it is just part of the element
>> expression.  I'm willing to discuss the merits of that decision, but the
>> fact remains that the semantics of destructuring binding and destructuring
>> assignment are quite different so I consider suspect any argument that
>> starts by assuming that they are the same.
> 
> Sorry, should have read the draft spec more thoroughly, I agree that
> assignment destructuring should have syntactic and semantic
> differences from binding destructuring.
> 
> However, I don't see why variable declaration array destructuring
> binding and parameter lists should be different in any way.  The only
> current syntactic difference between them is elision:
> 
> // allowed
> function f([,,,,,,x]){}
> // disallowed
> function f(,,,,,,x){}
> 
> The same syntactic inconsistency exists between array structuring and
> argument lists:
> 
> // allowed
> f([,,,,,,x]);
> // disallowed
> f(,,,,,,x);
> 
> The only semantic inconsistencies are:
> 
> * hole preservation (if function rest parameters do not, but array
> destructuring rest parameters do, as you suggest)
> * default value triggering:
> 
> // default not used
> (function(x = 0){})(...[,1])
> // default used
> var [x = 0] = [,1];
> 
> To me, eliminating these inconsistencies is a clear win, since it
> eliminates separate syntax and semantics for FormalParameterList and
> ArgumentList in the spec, implementations, and user's minds.  I would
> prefer to have elision, hole preservation, and defaulting based on
> input array length rather than holes, but only if they were
> consistently applied.
> 
> Thanks,
> Sean Eagan
> _______________________________________________
> es-discuss mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to