[[Class]] and host objects

Brendan Eich brendan at mozilla.com
Tue Feb 10 13:52:18 PST 2009

On Feb 9, 2009, at 6:29 PM, Waldemar Horwat wrote:

> Brendan Eich wrote:
>>> I’ve tried various formulation of a simple statement about host  
>>> objects but I keep finding potential holes and coming back to the  
>>> conclusion that the only meaningful thing to do is to explicitly  
>>> enumerable the invariants associated with each predefined  
>>> [[Class]] value.  Does anybody have a simpler solution?  Does  
>>> anybody want to volunteer to identify the invariants?
>> I think Chapter 15 already does identify the invariants, but you're  
>> right that multiple globals are not specified. In a single-global  
>> embedding, I would want any host [[Class]] == "Array" impostor to  
>> create instances whose prototype was Array.prototype, though.  
>> Wouldn't you?
> Not necessarily.  Array.prototype could be further up the prototype  
> chain, or perhaps they could share a common prototype that  
> constitutes a more generic kind of arrayness than Array.

I'm against such ontological confusion :-P.

It's true that almost all Array methods are generic (toString isn't,  
as seen below), but the custom [[Put]] in ES1-3, now [[ThrowingPut]]  
in 3.1, would be on a prototype and so would not be called when  
indexed properties were assigned to the directly referenced array-like  

js> a = []

js> o = {__proto__:a} // Object.create in ES3.1
Array.prototype.toString called on incompatible Object
js> o.toString = function()this.join(",")
function () this.join(",")
js> o

js> o[0]=0
js> o[1]=1
js> o

js> o.length
js> o[0]
js> o.hasOwnProperty(0)

A host object that has Array.prototype on its prototype chain could do  
more work by defining a [[ThrowingPut]] that maintains length, but the  
spec would have to say that such a [[ThrowingPut]] works exactly the  
same as the one spec'ed in

Object.getPrototypeOf would disclose a difference in prototype  
relations from "real" Arrays too.

There are several notions of "array-like" or "arrayness", where an  

* has a .length property whose uint32 value is one greater than the  
maximum uint32 conversion of any property name that converts back to  
the same string name.

* has a .length property that can be set to a lesser value than its  
current value to truncate or extend the set of indexed properties (not  
all would-be arraylikes can be truncated or extended in my experience).

* has the Array.prototype generic method suite, and possibly a  
toString that works the same as Array.prototype.toString.

* has Array.prototype on its prototype chain, either immediately or  
further up the [[Prototype]]-linked chain.

The meaning of [[Class]] == "Array" should include all of these, and I  
think Array.prototype should be the immediate prototype.

In implementations, [[Class]] corresponds to a native class (vtable)  
that implements [[ThrowingPut]], [[Prototype]], and other spec- 
internal properties. An implementation might be able to mix in  
different native classes but they would not be composed along the  
prototype chain. I'm not sure how the spec would even talk about such  
implementations, other than by doing what Allen said and requiring  
indistinguishability from native Array objects. Having Array.prototype  
as other than the immediate prototype breaks indistinguishability.


More information about the Es-discuss mailing list