Bait taken: Arguments about arguments

David-Sarah Hopwood david.hopwood at industrial-designers.co.uk
Wed Jan 14 20:00:32 PST 2009


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.

> 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.

> 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.

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

> 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.

> 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.

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.)

====
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 ⚥



More information about the Es-discuss mailing list