Bait taken: Arguments about arguments

Brendan Eich brendan at
Wed Jan 14 19:08:45 PST 2009

On Jan 14, 2009, at 2:54 PM, Mark S. Miller wrote:

> So let's imagine that we do nothing to "fix" arguments. How does  
> magic unfixed arguments play with the rest of the spec? Some  
> questions:
> 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 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, [...]
> Btw, that reference to 10.3.2 above looks like it should reference  
> 10.5 Arguments Object, which says
> > The arguments object is created by calling the abstract operation
> > CreateArgumentsObject with arguments [...]
> There is no separate definition of CreateArgumentsObject. Rather, it  
> seems its definition is the remaining text in 10.5. The spec here  
> for non-strict arguments gives it a [[Class]] of "Object" and a  
> [[Prototype]] of the original Array.prototype. It also,  
> mysteriously, gives in a [[Constructor]] of the Object constructor.  
> But there is no internal [[Constructor]] property!

These seem like easily fixed 3.1 bugs. File 'em?

> So, leaving aside the probably mistaken [[Constructor]] property,

.constructor must be what's meant.

js> function f(){return arguments.constructor}
js> f()
function Object() {
     [native code]

I'm not any more fond of this than you, but it is what it is.

> Function.prototype.apply has no semantic state to inspect in order  
> to carry out its spec.

When in doubt, use brute force. ES3 already did. Quoting from its spec  
for Function.prototype.apply: 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 object. If  
the object does not have a [[Call]] property, a TypeError exception is  

If thisArg is null or undefined, the called function is passed the  
global object as the this value. Otherwise, the called function is  
passed ToObject(thisArg) as the this value.

If argArray is null or undefined, the called function is passed no  
arguments. Otherwise, if argArray is neither an array nor an arguments  
object (see section 10.1.8), a TypeError exception is thrown. If  
argArray is either an array or an arguments object, the function is  
passed the (ToUint32(argArray.length)) arguments argArray[0],  
argArray[1], …, argArray[ToUint32(argArray.length)–1].

The length property of the apply method is 2.

> 2) What happens when you freeze an arguments 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, 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.

Yeah, Waldemar and I both pointed out (IIRC I did this first :-P) that  
this overspecifies arguments.

> Rather than fixing these issues, at Kona we decided instead not to  
> specify them in terms of getters and setters. But then, what does  
> Object.getOwnPropertyDescriptor(arguments, '3') return? If it claims  
> arguments[3] is a writable data property, then one should be able to  
> freeze it.


> Once frozen, does this prevent writing the corresponding parameter  
> variable?

No, not by assigning to the parameter name.

> Or does it sever the joining of arguments[3] and that parameter  
> variable?


> If instead it is specified with a non-configurable getter/setter  
> pair, then freezing does not affect it.

But that overspecifies.

> 3) What happens when you write to an object that inherits from an  
> arguments object?

No setters (overspecifies), so the same thing as today:

js> function f(){}
js> f.prototype = (function(){return arguments})()
[object Object]
js> o = new f
[object Object]
js> o[0] = 42
js> o[0]
js> function g(){}
js> g.prototype = (function(){return arguments})(1,2,3)
[object Object]
js> p = new g
[object Object]
js> p[0]
js> p[1]
js> p[2]
js> p[0]=4
js> p[0]
js> seal(p.__proto__)
js> p[0]=5
js> p[0]
js> g.prototype[0]=6
typein:19: Error: g.prototype[0] is read-only

(seal is a SpiderMonkey js shell function that calls an API to freeze  
the object in 3.1 terms.)

> Given
>     var sub = Object.create(arguments);
>     sub[3] = foo;
> does this assignment modify the parameter variable joined to  
> arguments[3]?

No, no setter in the prototype that is called instead of shadowed.  
Instead, shadowing as happens in ES1-3.

> Once again, if we think of arguments[3] as a data property, then the  
> answer should be no. 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.

Accessor overspecifies. Leave it underspecified and avoid malinvesting  
in arguments polishing!

> Whatever we do with strict arguments, we need to answer all three of  
> these questions for non-strict arguments anyway.

I tend to think the answers should be the same, although as noted in a  
previous message I'm open to the idea of freezing strict arguments.

> Until we settle the semantics of non-strict arguments, it's  
> premature to try to determine whether strict arguments can live with  
> that semantics.

Hope the above helps,

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

More information about the Es-discuss mailing list