However dynamic the js language might be, some things are still hard to do if not impossible. For example, one of the things that's currently impossible is to subclass some of the "magic" built in classes (Array, Function) and have the subclass instances behave as instances of their parents, but more. It's also impossible to cast an object into inheriting from another object after the object has been created*. This is where
__proto__
comes into play.
* You could swap prototype objects around, but that's not exactly what we're looking for, eh :)At some point (too lazy to google who/when exact ;)) browsers started to implement
__proto__
for this exact reason. As you know, each object has a hidden
[[Prototype]]
attribute (that syntax is only used in the spec, not in the actual language) which points to the
prototype
object of it's parent class, at least at object creation time.
For example:
var initialProto = {};
var Foo = function(){};
Foo.prototype = initialProto;
var child = new Foo();
log(child instanceof Foo); // true
log(child.[[Prototype]] === initialProto); // true, if this were valid syntax
Foo.prototype = {};
log(child instanceof Foo); // false!
log(child.[[Prototype]] === initialProto); // false, if this were valid syntax
log(child.[[Prototype]] === Foo.prototype); // false, we just changed it
So
instanceof
only cares about the magic link between a child's
[[Prototype]]
attribute and the parent's
prototype
property.
There's currently no formal way in js to change
[[Prototype]]
. But as I said, browsers have been introducing
__proto__
to work around this. Note that
__proto__
allows direct read-write access to the
[[Prototype]]
attribute. It allows weird constructs that you usually don't really need, but in some cases can't live without. For instance, in
Bikeshed, in the AS3 vm we use to run flash, we use
__proto__
to convert an object from one class to another by simply replacing the
obj.__proto__
by the prototype of the target class to convert to. And this works. Of course.
So what's my beef with
__proto__
? It's two-fold.
1: It's ugly fugly and I'd rather not see double underscores become part of the spec when there's no need. There's no precedence for them and they add to the whole grawlx argument.
2: More importantly, they break the invariant that an object in js can be used as a dictionary, without having to fear collisions. Yes,
for-in
collects from
Object.prototype
but that argument doesn't apply here.
__proto__
is the
only magic
own property objects get now. I have a problem with that because it's caused head aches for me while creating
Zeon. I keep a list in an object of all identifiers in the source code to look them up later. Try typing
__proto__
and see what happens.
I would prefer access to
__proto__
to be specced in a way that looks a bit more javascripty, you know?
So I've been discussing this last night for a bit with
Brendan,
Allen,
Alex,
David,
Axel and
Xavier.
I kicked it off
here. Allen
brings up the mobile argument. How the mobile platform won't adopt new changes any time soon. I
countered that this goes for anything new we spec right now.
I mean, if you don't spec changes, you can be certain it never disappears. No response.
I feel strongly about this. I'd rather respec
__proto__
into something that makes more sense and note that support of __proto__ is permitted (possibly even with an opt-out, but that's unlikely to fly...). Then eventually (in ten or twenty years) we might be able to drop
__proto__
. If we don't spec anything for it now we are sure that'll never happen.
Alex mentioned that support is wide spread. I hadn't kept up but last I knew Microsoft and Opera still hadn't implemented it.
Google seemed to agree but I couldn't quickly find recent articles. But it seems
ie10 will support it. I wouldn't be surprised if that spurred the sudden
discussion on es-discuss again (becoming a de-facto standard).
Brendan mentioned the es-discuss thread above and something went down there that I had already seen but tried to ignore. It seemed as if SES (Secure EcmaScript) was actually part of an argument to prevent sane implementations. The rationale is that a
__proto__
property is easy to delete from an object but a global
setPrototype
method would prevent SES in conjunction with non-SES (much like strict mode vs non-strict mode). At that time I was unaware that SES is actually
one of the five goals for es6 (ehr). It's a bit disappointing that this could very well be the sole reason that the dict invariant is broken. Sigh.
Instead there's a proposal to add a
new dict
type. Brendan
feels objects are not well suited as dicts. However, when I read that wiki page the only argument I see for that is
__proto__
. Are we running in circles?
Worse yet, when I look at the
dict proposal I read that dicts do NOTHING that objects can't already. The only difference is that
for-in
doesn't iterate over prototype. So just for that we introduce a new syntax (
{| .. |}
) and worse yet, a new response for
typeof
?? (
dict
). How the hell is that better than respeccing
__proto__
?
At some point I went to bed. In the morning I see the discussion was rounded up with the
usual argument. And I'm disappointed, as usual.
Time to head in a different direction. Time to push
my earlier idea of native browser support for compiling on-demand ("
native compiler api").