@@new

David Herman dherman at mozilla.com
Tue Jun 17 23:40:43 PDT 2014


Your proposal is appealing but I haven't convinced myself it works. There are a couple bits I haven't quite grokked.

> The special `constructor` method in ClassDeclaration/ClassExpression syntax
> would desugar to a static @@new method. This class:
> 
>    class Point {
>        constructor(x = 0, y = 0) {
>            this.x = x;
>            this.y = y;
>        }
>    }
> 
> would amount to this:
> 
>    class Point {
>        static [Symbol.new](x = 0, y = 0) {
>            var obj = super[Symbol.new]();
>            obj.x = x;
>            obj.y = y;
>            return obj;
>        }
>    }

You're inlining the method body into the @@new body, but I want to make sure I understand what the specification of the Point function itself would be. You've said Point !== Point[@@new] but calling Point(...args) should behave the same as new Point(...args). So then would the specification of the Point function's behavior just be to delegate to Point[@@new](...args)?

> The "super Arguments" call syntax in the ES6 drafts would be constrained to
> appear only at the top of a constructor, as in Java:

This part is what I'm the most unclear about. What invariant are you trying to maintain? It seems like you're using this to attempt to guarantee that all superclasses have had the chance to initialize their internal fields before user code starts running, so that built-in classes can have consistent internal representations and not have to worry about guarding against reading from uninitialized internal slots. But this is a tricky invariant to guarantee. First of all I think you'd have to put syntactic restrictions in place to disallow referring to `this` in the super call, to avoid e.g.:

  class Sneaky extends Date {
    constructor(x) {
      super((console.log(this.valueOf()), x));
    }
  }

But that's not enough, because you also have to worry about the superclass constructors calling overloaded methods:

  class Dupe extends Date {
    constructor(x) {
      super(x);
      initDupe();
    }
    initDupe() { ... }
  }

  class Sneaky extends Dupe {
    constructor(x) { super(x); }
    initDupe() {
      console.log(this.valueOf());
      super.initDupe();
    }
  }

(These are common pitfalls in languages that try to provide hard guarantees about field initialization. They come up, for example, in typed OO languages that try to provide guaranteed non-nullable fields.)

But maybe I'm misunderstanding what invariant you're aiming at?

> *   Base class constructors are always called.

Are you saying you would not only restrict the super call to the top, but require one to always be there? Or would an absence of a super call imply an implicit `super()`?

> *   These productions would be dropped from the ES6 grammar:
> 
>        MemberExpression : new super Arguments
>        NewExpression : new super

Clearly with your design `super[Symbol.new](...args)` is equivalent to `new super`. Is it also emulate-able in the @@create semantics also? If so it seems like the question of whether to keep or drop the `new super` syntax is 100% orthogonal to your proposal.

Dave



More information about the es-discuss mailing list