Finding a "safety syntax" for classes

Allen Wirfs-Brock allen at wirfs-brock.com
Mon Mar 26 12:03:07 PDT 2012


On Mar 24, 2012, at 11:45 PM, David Herman wrote:

> On Mar 24, 2012, at 5:54 PM, Allen Wirfs-Brock wrote:
> 
>> ...
> 
>>>   a) spell it "new" -- ergonomics trumps corner cases; hard cases make bad law
>> deviates from chapters 13 and 15.  
>> 
>> (class () {})  isn't interchangeable with (function () {}). Shouldn't it be?
> 
> When I say "spell it 'new'" I mean "the *surface syntax* is spelled 'new'". That has nothing to do with the semantics. The semantics is described in point b). Keep reading...

Ah, I was interpreting your a-d as 4 alternative semantics rather than as a sequence defining a single semantics.
> 
>>>   b) desugar it to the constructor function and the p.constructor property only
>> 
>> but presumably means that an instance method named new can't be defined using a class definition.
> 
> Not with the declarative syntax, no. But easily enough imperatively:
> 
>    class C { new(x) { this.x = x } } // defines C.prototype.constructor === C
>    C.prototype.new = function() { console.log("I am C's 'new' method") }

or
   class C{
       new() {this.x=x}
       "new"(){console.logn("I am C's 'new; method")}
   }

(not to say that I particularly like the above, but it would work according to the current strawman.)
> ...
> 
> My proposal is not, and has never been, to change the C.prototype.constructor idiom. It is to choose a different surface syntax that desugars to *exactly* the classic idiom.

Got it.

I'm still not necessarily convinced that giving new that syntactic meaning is the best thing to do.  The ES classabstraction is going to be a quite leaky abstraction.  Anyone will be able to easily observe that a class object is really a constructor function with a prototype property, etc. and this knowledge is probably going to needed even by fairly unsophisticated developer.  For example it is needed to understand the basic kind of class testings (a.constructor === b.constructor) that I mentioned.   My suspicion is that the name difference between the syntactic sugar and the underly but highly visible implementation will cause some confusion.  It also adds complexity because it requires addition static semantic rules regarding the use of new and constructor as method names within class declarations.

Finally, regarding:
>> 
>>> 
>>>    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.
>> 
>> I believe the constructor idiom is most commonly not followed today when the prototype property of a function is set to a new object (perhaps defined using an object literal) and correctly dynamically setting the "constructor" property is an extra step that is easily forgotten (an usually as no ill-effects) 

I really don't like d) very much at all.  I think one of the advantages that use of class declaration can offer  is a higher integrity implementation of the latent ES class model.   In particular, it could more strongly enforce the <ctor>.prototype === <ctor>.prototype.constructor invariant.  I don't think a class declaration should be allowed to set the prototype's constructor property to anything other than the actual class object (ie constructor function). It also should make <ctor>.prototype writable:false and configurable: false, just like is done for all of the chapter 15 constructors. In addition, I suggest that we should go one step further and also make <ctor>.prototype.constructor writable:false and configurable: false.  It isn't clear to me why ES1 chapter 15 made all <ctor>.prototype ReadOnly/DontDelete but didn't do the same for chapter 15 <ctor>.prototype.constructor properties.)Allen

Allen




More information about the es-discuss mailing list