Proposal to fix super and new inconsistency, future-proofing broader uses of new operator

Allen Wirfs-Brock allen at wirfs-brock.com
Tue Sep 3 09:28:25 PDT 2013


An interesting proposal, but I'm not yet sold. Here are some of the issue I see:

1) By "newing" a function an ES programmer is expressing a clear intent to use the body the body of the function as part of the instantiation process.  It would be counter intuitive to not execute the body of a constructor function when performing a new:

function C() {console.log("C constructed")};
...
//code somewhere else
C.prototype.constructor = function () {}
...
//back in the original script
new C;  //whoa why wasn't the constructor called

A class declaration is similar.  It defines (either explicitly or implicitly) the body of the class constructor.  It would be equally counter intuitive to not use that body when newing a class.

2) Some "classes" may not wish to expose an instantiation capability via their instances.  ES6 GeneratorFunctions are a good example this.  See lower right part of the diagram at http://people.mozilla.org/~jorendorff/es6-draft.html#sec-15.19.3 .  Each GeneratorFunction has an associated  prototype that is used by all of that GeneratorFunction's instances.  However, the prototype does not have a 'constructor' property.  This means that passing someone a generator instances doesn't give them the capability to instantiate additional instances of the same GeneratorFunction.  Whether class instances should expose the capability  to create additional instances of the same class is a design decision that situationally might go either way.  Exposing that capability via as the instance 'constructor' property is a fine default but isn't always the desirable alternative. Removing the prototype's 'constructor' property seems like a reasonable way to circumvent the default.  (BTW, a class whose prototype object does not have a 'constructor' property is similar, in concept, to a private constructor in Java).

> The second case is much more common: one redefines .prototype of a function, but does not define .constructor there (there was no real need). I would propose guard against this case - whenever the .prototype of a function is changed, the new would use old, legacy semantics. Constructor functions with non-changed .prototypes, as well as `class`es (which have .prototype non-writable) would work fine with the new, cleaner semantics.


3) I think the "second case" compatibility issue is very significant. Your fix basically requires that normal functions  have a distinct [[Construct]] internal method that ignores the 'constructor' property (just like the current spec.) while class objects would have to have a different [[Construct]] that dispatches via the 'construct' property.  So far we haven't had to make class objects (ie, functions) a different kind of exotic object from regular functions.  That means that class declarations are essentially just sugar and there is no real difference between an abstraction created using a class declaration and one composed out of more primitive function declarations and property accesses. I'd prefer not to lose that equivalence.

4) I'm reluctant to put additional property probes/access in the fast path of the 'new' operator.  Object instantiation should be fast and every extra property access or invocation costs something.  Maybe they can be optimized away, but maybe not...

Allen


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


More information about the es-discuss mailing list