Finding a "safety syntax" for classes

David Herman dherman at
Sat Mar 24 07:28:44 PDT 2012

On Mar 21, 2012, at 9:13 AM, Allen Wirfs-Brock wrote:

> On Mar 20, 2012, at 11:32 PM, David Herman wrote:
>> Well, hang on now. The 'constructor' syntax is not "just the constructor property." It still carries special status; the semantics of a class says "look for the property called 'constructor' and make that the [[Call]] and [[Construct]] behavior of the class."
> Actually, the semantics is probably more like:  the value bound to the <classMame>  is the function object defined by the <methodDefinition> whose <propertyName> is "constructor".

Yes, sure. Doesn't change the point: 'constructor' is still a special, distinguished method.

>> Regardless of whether we spell it 'constructor' or 'new' it requires special semantics that says "there's one distinguished method form in the body that determines the constructor of the class."
> There is one distinguished method that is the class object (aka, the constructor function).  A class declaration essentially desugars into the definition of a constructor function and a object that is the prototype associated with that constructor. 

Again, doesn't change the point: whether you spell it 'new' or 'constructor' it's still a distinguished method, and then you can desugar that however you want.

>> The question is how we spell that. This is 99.9% a surface syntax question. Tou could argue that spelling it 'new' should define a ["new"] method, or a ["new"] method and a ["constructor"] method, or just a ["constructor"] method. If the latter, it's semantically *identical* to spelling it 'constructor'. But even if we chose one of the other two alternatives, the semantic differences here are minor, and the ergonomics of the syntax matter.
> You need to drop the [ ]'s  (although I'm not sure what you meant by them...

I meant that there is a property of the prototype that you can access via either p["new"] or p["constructor"] or both, depending on which semantics we decide to give. No matter what the surface syntax, any of those semantics is available to us. I say:

    a) spell it "new" -- ergonomics trumps corner cases; hard cases make bad law

    b) desugar it to the constructor function and the p.constructor property only

    c) i.e., don't create a property -- no more prototype pollution please

    d) an explicit 'constructor' method overrides the implicit creation of the 'constructor' method but does not define the constructor function

Why d)? Remember, the .constructor idiom is a *very weak* idiom that many JS programs don't follow. If a JS program has some reason to use 'constructor' for a different purpose, trust them.

>>> Personally I think the answer should be "A" which implies that we have class-side inheritance.   This is a departure from current practice but because "classes are functions" there is no way in ES<=5.1  to set up class side inheritance other than by mutating __proto__.
>> I always found this the more appealing, but then again, if I'm supposed to be going with the opposite of my instincts (see above), then maybe I should disagree with you. ;)
> I would guess that your instinctive response comes from thinking about a "class" is something more than just  a composite of objects.  We can talk more about this later after I respond to Mark

I think you misread me. My instinctive response agrees with yours, not Mark's.

> If the value of SOMEEXPRESSION is a constructor function (typeof == "function" && and has a "prototype" property) then the new constructor inherits from SOMEEXPRESSION and the new prototype inherits from SOMEEXPRESSION.prototype.  Otherwise, the new consructor inherits from Function.prototype and the new prototype inherits from SOMEEXPRESSION.  That is essentially the semantics I've defined for
>        SOMEEXPRESSION <| function () {}

I'm not happy with that semantics, for either classes or <| (I believe others have objected on the list to the special-case semantics for <| as well). Since functions are objects, you can pass functions into contexts that expect an object and those contexts don't need to care whether the object they have is a function or an object. So this will lead to WTFjs moments where people take an object they got passed in from someone else and create a class with it, and it won't be wired up right because they didn't realize the object was a function.

This kind of special-case ad hoc type testing in the semantics has a bad smell. It reminds me of stuff like the Array constructor that special-cases the number argument.

> B = do{
>       let B = SOMEEXPRESSION <| function B(...) { ...};
>       B.prototype= SOMEEXPRESSION.prototype <| {constructor: B, ...}
>       B
> }
> (or to be maximally explicit}
> B= do {
>     let B = function B(...) {...};
>     if (typeof SOMEEXPRESSION == "function" && typeof SOMEEXPRESSION.prototype == "object") B.__proto__=SOMEEXPRESSION;
>     B.prototype= SOMEEXPRESSION.prototype <| {constructor: B, ...}
>     B
> }

Nit: you'd need to bind the result of SOMEEXPRESSION to a temporary, to avoid duplicating side effects. </macrology nerd>


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list