Allen Wirfs-Brock (2014-06-13T17:51:18.000Z)
On Jun 13, 2014, at 7:51 AM, Boris Zbarsky wrote:

> On 6/13/14, 6:33 AM, Tom Van Cutsem wrote:
>> As Allen mentioned, this came up a number of times in TC39 meetings and
>> I believe the fear for exotic objects that require control over
>> [[Construct]] was the biggest show-stopper. If more knowledgeable people
>> like Boris can vouch for the fact that this isn't the case, that would
>> remove the biggest roadblock.
> 
> The basic question is how that affects what WebIDL needs here is how it should play with subclassing.
> 
> If we don't care about subclassing WebIDL objects, there is no issue: WebIDL can just override [[Call]] as it does right now and we move on with life.  Note that some implementations at the moment override [[Construct]], not [[Call]] and just throw from [[Call]], so as to preclude web pages from relying on the current spec's [[Call]] behavior, since that would presumably interact badly with trying to introduce subclassing.

This "we" definitely cares about subclassing WebIDL objects and the ES6 object creation protocol was design with that in mind.

> 
> If we do care about subclassing, then presumably the "construct the right sort of object" and "initialize it" actions need to be somewhat decoupled for these objects.  It seems to me that both Allen's current spec and Jason's proposal accomplish that, right?

Right, Jason's proposal introduces an additional degree of variability that my proposal (assuming that [[Construct goes away) doesn't directly provide.  It kind of comes down to whether that extra flexibility is actually needed. 


> 
> In Jason's proposal it would look like this, if I understand it right:
> 
>  subclass[Symbol.new] = function(...args) {
>    // Modify args as desired.
>    var obj = superclass[Symbol.new](...args);
>    // Modify obj as desired.
>    return obj;
>  }

I don't think so. Unless, I misunderstand I don't think Jason is proposing eliminating @@create.  So, in most cases including, I believe, the WebIDL use cases  a constructor would simply use the default @@new that would be inherited from Function.prototype.  It's definition would be something like:

Function.prototype[Symbol.new] = function (...args) {
      let newObj = this[Symbol.create]();
      if (! IsObject(newObj) {
           //default handling for ill-behaved or missing @@create
      }
      let ctorResult = this(...args);
     if (IsObject(ctorResult) return ctorResult;  //ES<6 compatibility 
     else return newObj;
}

Note that this preserves the separation between object allocation and object initialization we need to make subclassing work correctly.

> which is pretty similar to how this would be done without classes:
> 
>  function subclass(...args) {
>    // Assume that we're being invoked via new.
>    // Modify args as desired.
>    var obj = new superclass(...args);
>    // Modify obj as desired.
>    return obj;
>  }

Except that the above doesn't give you true subclassing.  The object you return is an instance of the superclass and not of the subclass.  The key thing that @@create is doing is separating determining the physical characteristics of an object (making it exotic, branding it, using a custom C struct as its representation, etc.) from logically initializing it at an appropriate place within some class hierarchy 

> 
> except there is nothing that needs to be done if you don't want to munge args or obj, since not defining Symbol.new on the subclass will simply find it on the superclass.
> 
> In Allen's spec, it would look like this:
> 
>  "subclass constructor": function(...args) {
>    // "this" is already set to the right object that got created via
>    // looking up Symbol.create and calling it.
>    // Modify args as desired.
>    superclass.apply(this, ...args);
>    // Modify "this" as desired.
>  }
> 
> Is my understanding of the Allen and Jason's proposals correct?  I'd like to avoid making any claims of how these interact with WebIDL until I'm sure I'm not missing something important.

I think you are missing the key element @@create plays in both proposals.  The only real difference, I think, is whether you have to live with the default @@create/constructor protocol or whether you are allowed to tweak with that default.

Allen
domenic at domenicdenicola.com (2014-06-20T19:40:25.575Z)
On Jun 13, 2014, at 7:51 AM, Boris Zbarsky wrote:

> The basic question is how that affects what WebIDL needs here is how it should play with subclassing.
> 
> If we don't care about subclassing WebIDL objects, there is no issue: WebIDL can just override [[Call]] as it does right now and we move on with life.  Note that some implementations at the moment override [[Construct]], not [[Call]] and just throw from [[Call]], so as to preclude web pages from relying on the current spec's [[Call]] behavior, since that would presumably interact badly with trying to introduce subclassing.

This "we" definitely cares about subclassing WebIDL objects and the ES6 object creation protocol was design with that in mind.

> If we do care about subclassing, then presumably the "construct the right sort of object" and "initialize it" actions need to be somewhat decoupled for these objects.  It seems to me that both Allen's current spec and Jason's proposal accomplish that, right?

Right, Jason's proposal introduces an additional degree of variability that my proposal (assuming that [[Construct goes away) doesn't directly provide.  It kind of comes down to whether that extra flexibility is actually needed. 


> In Jason's proposal it would look like this, if I understand it right:
> 
> ```js
>  subclass[Symbol.new] = function(...args) {
>    // Modify args as desired.
>    var obj = superclass[Symbol.new](...args);
>    // Modify obj as desired.
>    return obj;
>  }
> ```

I don't think so. Unless, I misunderstand I don't think Jason is proposing eliminating @@create.  So, in most cases including, I believe, the WebIDL use cases  a constructor would simply use the default @@new that would be inherited from Function.prototype.  It's definition would be something like:

```js
Function.prototype[Symbol.new] = function (...args) {
      let newObj = this[Symbol.create]();
      if (! IsObject(newObj) {
           //default handling for ill-behaved or missing @@create
      }
      let ctorResult = this(...args);
     if (IsObject(ctorResult) return ctorResult;  //ES<6 compatibility 
     else return newObj;
}
```

Note that this preserves the separation between object allocation and object initialization we need to make subclassing work correctly.

> which is pretty similar to how this would be done without classes:
> 
> ```js
>  function subclass(...args) {
>    // Assume that we're being invoked via new.
>    // Modify args as desired.
>    var obj = new superclass(...args);
>    // Modify obj as desired.
>    return obj;
>  }
> ```

Except that the above doesn't give you true subclassing.  The object you return is an instance of the superclass and not of the subclass.  The key thing that @@create is doing is separating determining the physical characteristics of an object (making it exotic, branding it, using a custom C struct as its representation, etc.) from logically initializing it at an appropriate place within some class hierarchy 

> Is my understanding of the Allen and Jason's proposals correct?  I'd like to avoid making any claims of how these interact with WebIDL until I'm sure I'm not missing something important.

I think you are missing the key element @@create plays in both proposals.  The only real difference, I think, is whether you have to live with the default @@create/constructor protocol or whether you are allowed to tweak with that default.