delegating to typed objects

Brendan Eich brendan at mozilla.org
Mon Jul 9 21:55:25 PDT 2007


On Jul 9, 2007, at 9:09 PM, Kris Zyp wrote:

> I think it seems worth considering what a programmer is intending  
> if writes
> a function and defines a prototype for it. This is an explicit  
> action to
> create objects that inherit from the prototype object. If a user has
> specifically written code to inherit from c, wouldn't he expect to  
> inherit
> everything from c, including fixtures and methods (that work, not  
> throw
> incompatibility errors)?

Because it's possible to violate the type constraints on fixtures in  
the non-subclass object created by the function constructor?

That seems like a real possibility. The class methods, unless  
qualified by prototype, really do constrain the type of |this|, and  
that's a big part of the value of classes. Consider the alternatives:

1. Classes do not constrain types, have to check everything that  
might be different in a delegating object method call (|this|,  
members) at runtime.

2. Delegate creation via (new F) given F.prototype = new C and class  
C must make an instance of C, not of Object. This is not backward  
compatible.

3. Delegating to class methods from an instance created via (new F)  
somehow (how?) wraps the class methods with type-constraining  
wrappers, so the cost is not born by the class methods when called  
class instances.

I don't think any of these is a good plan.

> If we access fixture properties and methods just as
> we do do expando properties and functions, why wouldn't we expect
> programmers to want and fixtures and methods to be inherited?

Because fixture means fixed, unlike expando or ad-hoc properties. If  
you want to delegate without type constraints, you have the tools in  
JS already. Using classes means either locking down fields and  
methods, or (if you use dynamic and prototype qualifiers) emulating  
the ES1-3 builtins and stuff like the DOM classes. In the former  
case, you should get a type error. In the latter, you can do what you  
say you want, but you have to write the class with extra qualifiers.

> Defining
> prototypes is not something that just automatically happens in  
> places, but
> is a very intentional definition on the part of a programmer in  
> which they
> want and expect inheritance.

So is defining a class.

So is mixing the two definitions, constructor function prototype (not  
a definition but an assignment expression, of course) and class  
definition.

> And I still appeal to the symmetry and consistency of the "is"  
> operator
> operating exactly the same as the old instanceof operator when the  
> testing
> against a class:
> (a is C) == C.prototype is in a's delegate chain (at least when  
> __proto__
> has not been externally modified) that would be true with option 1.

The is operator tests whether its left operand is an instance of a  
subtype (<:, which is reflexive, so includes the type itself) of its  
right operand. It is not instanceof, which tests whether its left  
operand has a prototype equal to the value of the 'prototype'  
property of its right operand (if that operand is an object). Don't  
mention mutable __proto__ (it's a botch and irrelevant). Just consider:

function B() {}
function D() {}
D.prototype = new B
d1 = new D
assert(d1 is B)          // false
assert(d1 instanceof B)  // true
D.prototype = new Object
d2 = new D
assert(d2 is B)          // false
assert(d2 instanceof B)  // false

class B {}
class D extends B {}
d1 = new D
assert(d1 is B)          // true
assert(d1 instanceof B)  // true
D.prototype = new Object // silently fails because 'prototype'
                          // is DontDelete and ReadOnly in D
d2 = new D
assert(d2 is B)          // still true
assert(d2 instanceof B)  // still true

Not only can't you modify D.prototype, but (d1 is B) is true for  
class B but false for function B.

You are right that is and instanceof agree in all four assertions for  
classes. But only one of four corresponding assertions for  
constructor functions is true. Classes are not functions, not by a  
long shot.

/be



More information about the Es4-discuss mailing list