Must built-in prototypes also be valid instances? (Was: Why DataView.prototype object's [[Class]] is "Object"?)
brendan at mozilla.org
Sat Sep 29 17:17:56 PDT 2012
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
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)
but you can't get, has, set, size, or iterate Map.prototype:
typein:2:0 TypeError: get method called on incompatible Map
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
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
There are two separate issues here:
1. Should Map.prototype be an instance (firstborn for its realm) of
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
> 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.
More information about the es-discuss