Allen Wirfs-Brock wrote:
However, there is a bigger issue here.  You could have asked a similar  
question about Map.prototype.  Why isn't Map.prototype a Map instances? Is this 
a bug or an intentional design decision?

Historically, the prototype objects associated with the 9 named built-in 
constructors were all defined to be instances of those constructors.  For 
example, Boolean.prototype is a Boolean instance whose value is false.

In writing the specification for Map, I intentionally deviated from that 
pattern.

Failing to consult with implementors will just make editing churn. I don't remember much discussion on this change, if any -- we did talk about the general problem of prototype objects being firstborns of their class, and how this makes them sometimes not just basis cases but degenerate cases.

However, Map is prototyped in SpiderMonkey and V8. In SpiderMonkey, the prototype is a Map, not an Object:

js> Object.prototype.toString.call(Map.prototype).slice(8, -1)
"Map"

but you can't get, has, set, size, or iterate Map.prototype:

js> Map.prototype.get('x')
typein:2:0 TypeError: get method called on incompatible Map
js> Map.prototype.has('x')
typein:3:0 TypeError: has method called on incompatible Map
js> Map.prototype.set('x', 42)
typein:4:0 TypeError: set method called on incompatible Map
js> Map.prototype.size()
typein:5:0 TypeError: size method called on incompatible Map
js> for (var [k, v] of Map.prototype) ;
typein:6:13 TypeError: iterator method called on incompatible Map

The error message is suboptimal but what's going on here is that Map.prototype has the SpiderMonkey equivalent of [[Class]] == "Map" (or the ES6 equivalent). This is important since all the builtins in ES3 + Reality (including RegExp; ES3 deviated there) make the prototype for built-in class C be of class C.

Your change requires implementations to provide a different built-in class (constructor/prototype) initialization path. That's not desirable _per se_. Neither IMHO is the user-facing semantic split among "old" and "new" constructors.

There are two separate issues here:

1. Should Map.prototype be an instance (firstborn for its realm) of class Map?

2. Should Map.prototype be a key/value store that can be used or abused as any other Map could be?

We should not mix these up. SpiderMonkey (and possibly V8, I haven't tested) says "yes" to 1 and "no" to 2.

   I did not specify that Map.prototype is a Map instance.  While it has the 
methods that are applicable to Map instances it does not the internal state 
that is necessary for those methods to actually work.  For example, if you try 
to store a value into Map.prototype by calling its set method, you will get a 
TypeErrior according to the specification. May.prototype can not be used as a 
map object.

That doesn't mean Map.prototype should not be classified as a Map per 1 above.

Why did I do this?  Because, we are defining a significant number new built-in 
"classes" and it is going to be increasingly hard to define meaningful instance 
state for all such prototypes.

Not so, as shown above. It's trivial in SpiderMonkey to give the prototype no instance state and check for that. Alternative implementation techniques are feasible with different trade-offs.

Cc'ing implementors.

/be

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

Reply via email to