Bait taken: Arguments about arguments

Allen Wirfs-Brock Allen.Wirfs-Brock at microsoft.com
Thu Jan 15 12:06:41 PST 2009


At Tuesday's ES3.1 conference call we discussed the three major outstanding issues regarding the arguments object that had been discussed on this list and made decisions for incorporation into the "Mountain View" draft that was released earlier today.  These decisions were:
Ticket #428:  what does Array.isArray(arguments) return?  Decision - false
Ticket #447: should arguments object/formal parameter sharing continue after return?  Decision - yes
Ticket #448: should the sharing semantics of the arguments object differ for strict functions? Decision - no

At the time we thought these decisions reflected the emerging consensuses on the discussion list.  However, Mark Miller was not at the Tuesday meeting and at today's meeting he argued that the discussion list consensus for #448 seemed to be swing towards yes.

This would be a relatively straight forward change to the loatest draft specification. I suggest we make the decision at the Mountain View meeting after everybody has had a chance to review the current specification text.

The hard part about specifying arguments isn't any possible strict mode restrictions.  Instead, the challenge is understanding and specifying for normal (non-strict mode) the full impact of the ES3.1 enhanced object model (accessor properties, reified attributes, etc.) on the semantics of the arguments object.  I think we are very close to having it right now (but please review the spec. carefully) and most of the issues below are addressed so see my inline comments below.

>-----Original Message-----
>From: es3.x-discuss-bounces at mozilla.org [mailto:es3.x-discuss-
>bounces at mozilla.org] On Behalf Of David-Sarah Hopwood
>Sent: Wednesday, January 14, 2009 8:01 PM
>To: es-discuss at mozilla.org; es3.x-discuss at mozilla.org
>Subject: Re: Bait taken: Arguments about arguments
>
>Mark S. Miller wrote:
>> 1) Where is the semantic state that distinguishes magic arguments from
>other
>> array-like non-arrays that inherit from Array.prototype? There needs
>to be
>> such semantic state, to account for the acceptability of arguments as
>the
>> second argument of Function.prototype.apply, to whit:
>>
>> (From 15.3.4.3 of 22dec08 draft)
>>> Otherwise, if argArray is neither an array nor an arguments object
>(see
>> 10.3.2),
>>> a TypeError exception is thrown. If argArray is either an array or an
>> arguments
>>> object, [...]
>
>That can be fixed by making Function.prototype.apply accept any array-
>like
>object (i.e. only read the .length and array index properties of
>argArray).
>I've previously suggested wording for that, which is repeated at the end
>of this email.

This is already adequately addressed by the current specification which consistently speaks about the "arguments object".  We could invent a seemingly more formal specification device to identify arguments object (for example using a [[ArgumentsObject]] internal property to tag them) but that really doesn't add anything. These are all just specification devices (it's up to an implementation to figure out how to achieve the specified semantics) and I don't see any real ambiguity in the specification about which objects are "arguments objects".

That said, I do think there is ambiguity about what is required of the second argument to Function.prototype.apply.  As there seems to be a subthread specifically on that, I'll save my thoughts for there.


>
>> 2) What happens when you freeze an arguments object?
>
>I don't think this presents any problem: the synthesized getter/setter
>properties are made non-[[Configurable]] and the object is made
>non-[[Extensible]], just like when freezing any other object.
>
>> In the Kona draft (and still in the 22dec08 draft), the joining of
>> non-strict arguments with the parameter variables is specified by
>> synthesizing getter/setter functions. At the Kona meeting, Waldemar (I
>> think) pointed out 1) that the way this was specified had inadvertent
>> non-hygienic lexical variable capture problems,
>
>Why is it non-hygienic? It captures the variables, certainly, but it's
>supposed to.
>
>> and 2) given the new
>> attribute revelation APIs, such explanatory getters and setters could
>be
>> reified, requiring us to specify whether they're frozen, when they're
>===,
>> etc.
>
>Seems fine to me. Don't we *have* to specify what attributes they have?
>An arguments object should not be a magical special case for attribute
>reflection. The behaviour of === is already clear in the 22 December
>draft,
>because it specifies that the getters/setters are initialized as-if by
>creating new functions.

The current draft still uses closures to model the sharing semantics but is now very careful to not expose them. If examined using getOwnPropertyDescriptor the indexed arguments properties appear as data properties. If a property is modified via Object.defineProperty or delete the sharing semantics is "broken" when appropriate.  This is consistent with existing implementations which appear to "disconnect" arguments indexed properties that are deleted and then subsequently recreated. After talking with Mark at today's meeting I think there is one addition case that isn't accounted for in the current draft: setting [[Writable]]:false doesn't currently break sharing for an arguments property.  It should.  I'll ticket this as a bug in the current draft.

>
>> 3) What happens when you write to an object that inherits from an
>arguments
>> object?
>>
>> Given
>>     var sub = Object.create(arguments);
>>     sub[3] = foo;
>>
>> does this assignment modify the parameter variable joined to
>arguments[3]?
>> Once again, if we think of arguments[3] as a data property, then the
>answer
>> should be no.

No is the answer that is implemented in the latest draft.  All the normal semantics of assignment to inherited data properties work (according to the specification) for inherited indexed arguments object properties.

>
>(Non-strict) arguments properties are not data properties, period. They
>can't be because that would not result in the required aliasing with
>parameters.

For purposed of reflection they have to be either data properties or accessor properties because that is all we have. In the latest spec. they manifest themselves via getOwnPropertyDescriptor as data properties. Rather than thinking of them as accessor properties it is probably better to think about them as data properties that are being continually monitored by some agent which updates them to reflect changes to the corresponding formals

>
>> We've instead created a new own '3' property on sub and have
>> not affected its parent. But if we think of it as an accessor
>property, then
>> this assignment should invoke the inherited setter.
>
>Right. This is arguably a little bit overspecified, but mostly harmless.
>

See above, they act as data properties

>> Whatever we do with strict arguments, we need to answer all three of
>these
>> questions for non-strict arguments anyway.
>
>I agree; I just think the current wording already does answer these --
>subject to the Function.prototype.apply fix below, which is
>independently
>useful.

The ES3 spec. certainly does answer these, it doesn't have accessor properties or user settable property attributes so it couldn't address these issues at all.  Also it doesn't explicitly address any of the ambiguous edge cases of what it means when it says "the property shares its value with the corresponding property of the activation object". The Kona draft manifested the argument properties as accessor properties but that has now been fixed.

>
>There should be a Trac issue for Function.prototype.apply; I'll be busy
>for the next couple of days, so feel free to add one.
>
>----
>The following changes
> - make apply handle its argArray generically;
> - rewrite apply and call using the algorithm notation;
> - clarify that apply and call return the return value of the called
>   function;
> - acknowledge that there may be an implementation-defined limit on
>   the number of arguments to a function. (This also needs to be fixed
>   in section 11.2.4.)
>

I generally agree, these really should be specified algorithmically.  Otherwise we don't really know how they're supposed to work for edge cases such as sparse arrays.   If we had an algorithmic specification we probably won't need to worry about restricting the second argument to arrays and arguments objects.


>====
>15.3.4.3 Function.prototype.apply (thisArg, argArray)
>
>The apply method takes two arguments, thisArg and argArray, and performs
>a function call using the [[Call]] property of the this object, by the
>following steps:
>
>1. If IsCallable(this) is false, then throw a TypeError exception.
>2. If argArray is null or undefined, then
>     a. Call the [[Call]] method of this object, providing thisArg
>        as the this value and no arguments.
>     b. Return Result(2a).
>3. If Type(argArray) is not Object, then throw a TypeError exception.
>4. Call the [[Get]] method of argArray with property name "length".
>5. Let n be ToArrayLength(Result(4)).
>6. If n is greater than an implementation-defined limit on the number
>   of arguments to a function, then throw a RangeError exception.
>7. For every nonnegative integer k less than n:
>     a. Let P_k be ToString(k).
>     b. Let arg_k be the result of calling the [[Get]] method of
>        argArray with property name P_k.
>8. Call the [[Call]] method of this object, providing thisArg as the
>   this value and arg_0, arg_1, ... arg_{n-1} as the arguments.
>9. Return Result(8).
>
>The length property of the apply method is 2.
>
>
>15.3.4.4 Function.prototype.call (thisArg [ , arg_0 [ , arg_1, ... ] ] )
>
>The call method takes one or more arguments, thisArg and (optionally)
>arg_0, arg_1 etc., and performs a function call using the [[Call]]
>property of the object, by the following steps:
>
>1. If IsCallable(this) is false, then throw a TypeError exception.
>2. Call the [[Call]] method of this object, providing thisArg as the
>   this value, and any remaining arguments to the call method starting
>   with arg_0 (if provided) as the arguments.
>3. Return Result(2).
>
>The length property of the call method is 1.
>====
>
>--
>David-Sarah Hopwood ⚥
>
>_______________________________________________
>Es3.x-discuss mailing list
>Es3.x-discuss at mozilla.org
>https://mail.mozilla.org/listinfo/es3.x-discuss


More information about the Es-discuss mailing list