Allen Wirfs-Brock wrote:
On Oct 1, 2012, at 12:21 PM, Brendan Eich wrote:
...
The best reason for using Object is the one Mark raised: class (as sugar for
constructor/prototype) uses Object.
But if you've read the thread this far, my objective is not to enforce one
implementation approach or the other. It's to use @@toStringTag and anything
like it so there's no observable difference between the two approaches. Classes
should be able to do likewise.
Otherwise we have
class C extends B {...}
and
C.prototype instanceof Object
when the cowpath today wants
C.prototype instanceof B
I'm not sure what you are arguing for/against with the above point about
instanceof.
I'm not arguing "for" or "against" yet, just observing that we can't
rule out the possibility that a class constructor.prototype is *not* a
plain old Object instance, and (if B has mutable state hidden behind
accessors) presents the side channel Mark pointed out.
instanceof is it's own mechanism that is independent of toString, [[Class]] tagging, or any
concept that is used in section 15 of ES<=5.1 when it is talking about instances of the
various built-ins. About the best you can do is create a table that compares all the
various mechanism that do something like an "instance of" check against the actual
built-in and look for the consistencies/inconsistencies.
Yes, the toString tagging is separate and can be handled (we should
decide how it should be handled, though. Is C.prototype.constructor ===
C even though C.prototype instanceof B not C?).
The side channel issue remains.
The current spec. language for class definitions would produce true for
C.prototype instanceof B and false for C.prototype instanceof C.
Right, and this is saner than the builtins which also have !(C.prototype
instanceof C) but also tag such that TagOf(C.prototype) === "C".
But it would also answer true for C.prototype instanceof Object and
B.prototype instanceof Object.
One would hope so! :-P
If there is an inconsistency here, it is that C.prototype claims to be
instanceof B but in fact probably hasn't been initialized using the B
constructor so it can't actually behave as a B instance.
FWIW, here's what CoffeeScript generates:
(function() {
var B, C,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if
(__hasProp.call(parent, key)) child[key] = parent[key]; } function
ctor() { this.constructor = child; } ctor.prototype = parent.prototype;
child.prototype = new ctor(); child.__super__ = parent.prototype; return
child; };
B = (function() {
function B() {}
B.prototype.p = 42;
return B;
})();
C = (function(_super) {
__extends(C, _super);
C.prototype.q = 99;
function C(p, q) {
this.p = p;
this.q = q;
}
return C;
})(B);
console.log(C.prototype instanceof B);
}).call(this);
The __extends function copies class-side heritables but then sets
child.prototype = new ctor(), so interposes a new Object instance with
shadowing constructor = child in between child.prototype and
parent.prototype.
This is "just" informative, but now that I look at it, it seems to me to
avoid the mutable state side channel, provided B.prototype is
(inductively) an Object instance. Neat!
/be
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss