Finding a "safety syntax" for classes

Allen Wirfs-Brock allen at wirfs-brock.com
Tue Mar 20 18:59:17 PDT 2012


Perhaps surprisingly to some, I can easily get behind this proposal  (or even in front of it) as long as we stick to pretty much the absolute minimum requires (and design) as outline in Russell's original message.  We need to think of this as declarative syntax for just the  constructor function+populate the prototype methods pattern that is commonly used today.  Nothing more than that.  As I scanned other message in this thread, I found my eyes glazing over on the message that talk about any sort of substantial change or embellishment.  If we go down that path, we will just get stuck in the swamp again.  I think the only variations in Russell proposal that we should consider are things (if any) that can be clearly explained as being future hostile.  (or any outright bugs...)

Regarding Dave's concern:
On Mar 20, 2012, at 11:55 AM, David Herman wrote:

> I can mostly dig it -- I've been trying to encourage minimal classes for quite some time now.
> 
> The part that I'm least happy about is that this doesn't allow for declarative private methods, because if we had the computed syntax like what we're adding to object literals, it would clash with hoisting:
> 
>     {
>         let priv = new Name();
>         class C {
>             // oops, priv is still undefined!!
>             [priv](x, y, z) {
>                 return x * y / z
>             }
>         }
>     }
> 
Dave, It shouldn't be an issue.  As has been discussed in other threads (and at least one TC39 F2F) hoisting class definitions and immediately initializing them the way we do with functions just doesn't work. Well, more precisely, it doesn't work for full featured class declarations with things like initialized data properties (class or instance side).  Maybe we could get away with it with this limited form but then that would be future hostile to future extensions that try to grow it into a full bells and whistles class declaration. 

We can live quite nicely with treating class declaration like const declarations.  The name is logically hoisted so it is visible over the lexical scope, but the name is temporally dead until the class declaration is executed, in statement sequence, as an initializer.  That means that we can have circular references between classes and forward references in inner functions to classes.  The class declaration just need to be initialized before any such reference is actually evaluated. Its TDZ for classes.

Practically, that means that super classes declarations have to appear in the text before subclasses and that you probably can't tuck all your class declaration at the end of the block/function (yuck, anyway) like you can with function declarations.  I think we can live fine with that.  

Regarding privates, if classes are initialized in that manner there shouldn't be any problem with the pattern you use for in your example above.  It works exactly the same as for object literals.


> But I suppose the answer to that would eventually be better declarative syntax for `private`, as we've discussed but deferred for post-ES6 consideration.
> 
> I do think that class declarations should be hoisted, both in the sense of being in scope for the whole containing block (as with let and function) and in the sense of being initialized before the block begins executing (as with function).
> 
> 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.

> 
> * short & sweet
> * consistent with get/set shorthand
> * already a keyword so it can be given special treatment
> * doesn't have to actually correspond to a property called "new", so no extra magic properties on top of .constructor
> * can still create a .constructor property as well

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

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

To wrap up, this look really promising if we can restrict the feature scope in the manner Russell suggests.  Hey, I could knock this off and have it in the spec. draft in a couple days work.  There just isn't that much to it.

Allen


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


More information about the es-discuss mailing list