Allen Wirfs-Brock (2013-12-27T19:27:12.000Z)
On Dec 24, 2013, at 6:41 PM, Sebastian Markbåge wrote:

> This is an esoteric and ugly use case but I'm not trolling. The default constructor for a class which extends another is:
> 
> constructor(...args){ super(...args); }
> 
> Is there any reason it shouldn't return the value from super?
> 
> constructor(...args){ return super(...args); }
> 
> Basic constructors still have the quirky behavior of ES functions that they can return any object and don't have to return the instantiated object. This can be useful if they're used as functions or should return a placeholder object, or other instance, for compatibility/legacy reasons. E.g. when you have a custom instantiation process.
> 
> class Foo { constructor() { return {}; } }

This sort of allocation in the constructor body of a class definition will probably come to be viewed as an anti-pattern.   Note that:
       new Foo instanceof Foo
would evaluate to false given the above class definition.  Also, the Foo.prototype would not be on the prototype change of the returned value. 

There is a new factoring of responsibility and associated usage patterns that come along with ES6 class definitions.  We should no longer think in terms of a constructor function having the responsibility for both providing a new instance and initializing its state.  It is the responsibility of the @@create method to provide the object that is returned by the new operator.  The primary responsibility of the constructor body is to initialize that object. 

A better definition of the above Foo would be:

      class Foo {static [Symbol.create]() {return {}}}

However definition still produces instances that fail the instanceof test, so perhaps what you really want would be:

      class Foo {static [Symbol.create]() {return {__proto__: this.prototype}}}

It is difficult to design of a constructor body that behaves correctly in all five of these situations:  invoked via the new operator; invoked with a super call from a subclass constructor;  called directly; called via call/apply function with arbitrary things passed as the this value; and, called as a method. The ES6 spec. has to handle all for of those use cases for the legacy built-in constructors.  But I don't think we want to encourage people to do so for new abstractions defined using ES6 class definitions because in most cases what they produce will be buggy,

The usage patterns we should be teaching for class abstractions in ES6 are:

1) Always use the 'new' operator to create instances of a class.
2) Never call a class directly by name without 'new.
3) Class constructor bodies should initialize the instance object that are passed to them.
4) Class constructor bodies should only be called by the 'new' operator or as a 'super' call from a subclass constructor body.
5) [experts] Define a @@create method if you need your class to have special allocation behavior. 

Also, don't model your classes after Array, Date, RegExp, Error, etc. as they violate these rules. Unlike those built-ins,  don't design your classes such that 'new' is optional. It is hard to get that right while still permitting subclassing. 

Regarding adding 'return' to the default constructor body.  It appears that technically it would be a benign change.  However, the only reason to do so would be accommodate superclasses that deviate from the above patterns.  In that case, you are probably already in the weeds.  I'm not sure that we should be trying to facilitate such deviations. 

> Currently, this behavior doesn't carry over to subclasses by default:
> 
> class Bar extends Foo {	}
> 
> You'd have to explicitly define a constructor that returns the value from the super call.
> 
> Additionally, since DefineMethod is going to be exposed, does it make sense to expose ReferencesSuper too?
> 
> Otherwise there is no way to detect, at runtime, if a default constructor function is a top-level constructor (without a super), or a subclass with a super. One of them can use toMethod but not the other.
> 

Can you describe the use case you are thinking about here?  The decision to do a super call in a constructor is normally a design time decision made by a programmer. 

allen
domenic at domenicdenicola.com (2014-01-06T16:29:22.067Z)
On Dec 24, 2013, at 6:41 PM, Sebastian Markbåge wrote:

> This is an esoteric and ugly use case but I'm not trolling. The default constructor for a class which extends another is:
> 
> ```js
> constructor(...args){ super(...args); }
> ```
> 
> Is there any reason it shouldn't return the value from super?
> 
> ```js
> constructor(...args){ return super(...args); }
> ```
> 
> Basic constructors still have the quirky behavior of ES functions that they can return any object and don't have to return the instantiated object. This can be useful if they're used as functions or should return a placeholder object, or other instance, for compatibility/legacy reasons. E.g. when you have a custom instantiation process.
> 
> ```js
> class Foo { constructor() { return {}; } }
> ```

This sort of allocation in the constructor body of a class definition will probably come to be viewed as an anti-pattern.   Note that:

```js
new Foo instanceof Foo
```

would evaluate to false given the above class definition.  Also, the `Foo.prototype` would not be on the prototype chain of the returned value. 

There is a new factoring of responsibility and associated usage patterns that come along with ES6 class definitions.  We should no longer think in terms of a constructor function having the responsibility for both providing a new instance and initializing its state.  It is the responsibility of the @@create method to provide the object that is returned by the new operator.  The primary responsibility of the constructor body is to initialize that object. 

A better definition of the above Foo would be:

```js
class Foo {static [Symbol.create]() {return {}}}
```

However definition still produces instances that fail the instanceof test, so perhaps what you really want would be:

```js
class Foo {static [Symbol.create]() {return {__proto__: this.prototype}}}
```

It is difficult to design of a constructor body that behaves correctly in all five of these situations:  invoked via the new operator; invoked with a super call from a subclass constructor;  called directly; called via call/apply function with arbitrary things passed as the this value; and, called as a method. The ES6 spec. has to handle all for of those use cases for the legacy built-in constructors.  But I don't think we want to encourage people to do so for new abstractions defined using ES6 class definitions because in most cases what they produce will be buggy,

The usage patterns we should be teaching for class abstractions in ES6 are:

1. Always use the 'new' operator to create instances of a class.
2. Never call a class directly by name without 'new.
3. Class constructor bodies should initialize the instance object that are passed to them.
4. Class constructor bodies should only be called by the 'new' operator or as a 'super' call from a subclass constructor body.
5. [experts] Define a @@create method if you need your class to have special allocation behavior. 

Also, don't model your classes after Array, Date, RegExp, Error, etc. as they violate these rules. Unlike those built-ins,  don't design your classes such that 'new' is optional. It is hard to get that right while still permitting subclassing. 

Regarding adding 'return' to the default constructor body.  It appears that technically it would be a benign change.  However, the only reason to do so would be accommodate superclasses that deviate from the above patterns.  In that case, you are probably already in the weeds.  I'm not sure that we should be trying to facilitate such deviations. 

> Currently, this behavior doesn't carry over to subclasses by default:
> 
> ```js
> class Bar extends Foo {	}
> ```
> 
> You'd have to explicitly define a constructor that returns the value from the super call.
> 
> Additionally, since DefineMethod is going to be exposed, does it make sense to expose ReferencesSuper too?
> 
> Otherwise there is no way to detect, at runtime, if a default constructor function is a top-level constructor (without a super), or a subclass with a super. One of them can use toMethod but not the other.

Can you describe the use case you are thinking about here?  The decision to do a super call in a constructor is normally a design time decision made by a programmer.