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

Reply via email to