On __proto__

2012-05-28

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:

Code:
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").