Good-bye constructor functions?

Herby Vojčík herby at mailbox.sk
Mon Jan 7 16:09:14 PST 2013



Allen Wirfs-Brock wrote:
> OK, I ready you proposal.  I'll summaries it:
>
> class Sub extends Super {
>     constructor (...args) {
>         super(...args);  //or super.constructor(...args)  because they mean the same thing.
>    }
> }
>
> creates an (almost) ordinary object that is the initial value of the Sub binding.  The [[Prototype]] of Sub is the value of Super. Sub is created with a "prototype" property whose value is a new ordinary object whose [[Prototype]] values is Super.prototype.  Sub.prototype has a method property named "constructor" whose value is a super bound method function with the user specified body.  There is nothing special about this method, it it just like any other method defined in a class declaration.  In particular it does not have a [[Construct]] internal property.
>
> The only thing exotic about Sub is that the object has a [[Construct]] internal method.  It does not have a [[Call]] internal method.  The definition of its [[Construct]] in almost JS pseudo code is:
>
>        //internal method  this.[[Constructor]](argList):
>        let newObj = this.@@create();  //eg Sub.@@create();
>        let replacementObj = this.prototype.constructor.apply(newObj, argList);
>        if (typeof replacementObj == "object"&&  replacementObj !== null) return replacementObj
>        return newObj;
>
> Implications:
>     Sub === Sub.prototype.constructor evaluates to false.
>     To create a new instance of Sub say:
>             new Sub()
>     The following is a TypeError, because Sub does not have a [[Call]] internal method:
>            Sub()
>     The following is a TypeError, because Sub.prototype.constructor does not have a [[Construct]] internal method:
>             new Sub.prototype.constructor()
>      Sub.prototype.constructor can be called directly or as a method invocation including via a super call a subclass of Sub.
>
> It seems to me, all you have accomplished here is to make it illegal
> to call a class object directly as a function. If we were starting

 From technical PoV*, yes.
Oh, and I fixed the super / new inconsistency.

> over that might be a reasonable design choice. But we have a legacy
> to consider. Even if we think we should discourage direct calls to

Ignoring Foo.call(this) replacable by super, mostly, "class" is used for 
new Foo and for Foo.staticVar. I argued the change is big in its wider 
implication, even scary, maybe (but I see it as in fact minimal), but 
should not (imo) beat legacy much; because the fact of the tight 
coupling was not exploited so much.

> class objects (I think I'm now in that camp) actually making it an
> error seems like it may be too big of a step away from the legacy
> conventions.

And there is no better time to do that step than now, when class is new 
construct in the language.

*There is more than narrow technical PoV.  By returning plain object 
with exotic [[Construct]], working in nearly every detail as a class, 
while affording not to be the constructor itself, you effective say 
openly "You can use any [[Construct]]ified object as a class in ES6+. 
Gates are finally open".

It can be blessed by Reflect.makeClass(classObject, protoObject) or 
similar API.

It can bring lots of new patterns and cowpaths into the language.
If people don't want plain object to be the class, but their existing 
object x, they do
   Reflect.makeClass(x, (class {...}).prototype);

and they then can `new x`. They choose what they will use as x for new 
operator; because now class is one object and constructor is another.

For example, the criticized pattern of 'function that does differently 
for [[Call]] and [[Construct]]' could now be created as well. Just 
'makeClass' it.


The main message of this proposal is that beyond fixing super/new 
inconsistency, it opens new world for "classes", not restricted by the 
legacy tightly bound class===constructor objects.

And by making class to return this kind of 'decoupled' classes, this 
widened view to "who may be used as a class in new / extends?" is 
effectively blessed.

You cannot open it later. Because there will be lagacy code that already 
uses `class`.

(I'd stress again, that, imo, that change is very little, too little for 
the fruits it can bear. Fix me if it breaks something critical)

> Allen

Herby


More information about the es-discuss mailing list