Hello!

PROBLEM
====

In the present state of the spec, there is little inconsistency between behaviour of new and super.

What these operation roughly do is:

  new Foo(...args) is
    Foo.call(Foo[@@create](), ...args)
  super(...args) inside constructor is
    __superclassproto__.constructor.call(this, ...args)

This is elegant and consisten solution - super behaves as in any other method - calling superclass's version of itself.

Since Foo.prototype.constructor is set to Foo by default, no inconsistency is observed in default case - super(...args) calls the same function from subclass of Foo and in new Foo.

But if constructor is changed (or deleted / not defined), inconsistency appears - new still calls Foo, but super calls different function (or fails if there is no .constuctor in proto chain).

My gut feeling is that new Class and super in SubClass should do the same thing. Also, if this IMO bug begins to be exploited, to "have different initialization of own instance versus subclass one", there is no way back.

SOLUTION
====

There is elegant solution for this by redefining new to do roughly:

  new Foo(...args) is
    Foo[@@create]().constructor(...args)

Compared to previous semantics, this is much cleaner and understandable, and in par with super philosophy of "treat 'constructor' as just another method".

For default cases, this works identically with the formed definition.

For `class` keyword, if you change constructor method of an existing class, this semantics nicely implements your intent - to change the way howe class Foo is initialized (in both new and super).

Remaning scenario is changed .constructor of constructor function.
Here, it can be changed directly (you change .constructor of existing .prototype) or indirectly (you change .prototype of the constructor function). Both would break existing web.

The silent assumption of this proposal is, that the former case (changing .constructor of default .prototype) is rare if it ever appears, though I did not search for this.

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.

FUTURE PROOFED BROADER NEW
====

This change decoupled the need of the Foo in `new Foo` being callable - so the new semantics of new allows any object having @@create defined to be usable inside new - the initialization of the instance is nothing more than just calling 'constructor' method with appropriate args, so the new instance is responsible for initializing itself, no matter who was its creator/allocator.

ISSUES
====

1. It is not known if the case of changing .prototype.constructor without changing .prototype itself on legacy constructor functions is really rare or it has its legitimate use and is spread. 2. Instance does not know its creator/class (you cannot do generic 'new this.constructor(...args)').

Herby
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to