Finding a "safety syntax" for classes

Allen Wirfs-Brock allen at wirfs-brock.com
Wed Mar 21 09:13:11 PDT 2012


On Mar 20, 2012, at 11:32 PM, David Herman wrote:

> On Mar 20, 2012, at 6:59 PM, Allen Wirfs-Brock wrote:
> 
>> On Mar 20, 2012, at 11:55 AM, David Herman wrote:
> 
> 
>>> My only syntactic quibble: `constructor` is so inconveniently long. I've argued in the past for `new` as special syntax in class bodies that indicates a constructor.
>> 
>> Well, it is defining the value of the constructor property.  New syntax (eg, new) could always be added latter.  I don't think we should risk derailing on it now.
> 
> 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".

> 
> 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. 

> 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...

The existing "class pattern" in ES<=5.1 says that we need to have a property named  "constructor" on the prototype object whose value is the actual constructor function (which is also the object that is bound to the class name).  Even if we used new as a keyword to designate the declaration that provides the body of the constructor function we would still have to create a property on the prototype named "constructor". We could do this but it opens up other others just has what if we use "new" to designate the constructor function declaration and  "constructor" is explicitly used as the name of one of methods?

We could deal with those issue and I'm not particularly opposed to using "new" as a designator.  However the reason I pushed back against considering it was that I don't want this to become the sort of issue that derails this whole approach.  On the other hand, it does seem like a decision we have to make now, if ever.  If we don't give "new" special meaning now then people can define methods named "new" (on the prototype) and backwards compatibility would prevent us for giving "new" special meaning in the future. 


> 
> Look, it won't be the end of the world if we go with 'constructor'. This particular question won't derail classes. But let's not tax the ergonomics for what would be either a tiny or even non-existent semantic difference.
> 
>> So here is my one possibly future hostile (or we need to decide now) issue:
>> 
>> class A {};
>> A.classProperty="A";
>> class B extends A {};
>> Console.log(B.classProperty);   //"A" or undefined??
>> 
>> I don't believe Russell said, one way or the other.  Potentially either way could be seen as future hostile if you think the "right" answer is the other one (and we have to do something in this regard).
> 
> Agreed; this is a decision we can't defer if we support `extends`.
> 
>> 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


> 
> Seriously, though, Mark's concerns are valid. (On a semi-related note, I intend to try an alternative of the binary data API with no meta-classes.) We can work through this issue.
> 
>> We could make an accommodation that this only occurs if the "superclass" object is a function.  Otherwise, the "superclass" is only uses as the [[Prototype]] of the prototype and the constructor function simply inherits from Function prototype.   BTW, I assume the thing the the right of extends  is an expression.
>> 
>> So, if you could say:
>> class B extends A.prototype {}
>> 
>> if you don't want the class-side inheritance
> 
> Wait, I don't see how that could work. If the RHS of `extends` is an arbitrary expression, and we allow the programmer the freedom to provide either a super-class or a super-prototype, how do we know what the prototype's prototype is? IOW, it's ambiguous whether to treat:

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 () {}
> 
>     class B extends SOMEEXPRESSION { ... }
> 
> as:
> 
>     B = do {
>         function B(...) { ... }
>         B.prototype = SOMEEXPRESSION <| { ... }
>         B
>     }
> 
> or:
> 
>     B = do {
>         function B(...) { ... }
>         B.prototype = SOMEEXPRESSION.prototype <| { ... }
>         B
>     }
> 

B = do{
      let B = SOMEEXPRESSION <| function B(...) { ...};
      B.prototype.{...}
}

(or do avoid Dave gagging on .{  ;-)

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
}
   
Allen






> Dave
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120321/b6030748/attachment.html>


More information about the es-discuss mailing list