A strawman for subclassing

# David Bruant (14 years ago)

The subclassing native constructor issue came out several times on the list and on the web. However, I do not see a strawman for this. There are strawman:array_create and strawman:array_subtypes, but no mention of a generic solution.

From the "standardizing proto" thread [1], I retained two

interesting generic solutions:

  1. Olivier Hunt at esdiscuss/2011-March/013141 Object.subclass = function(constructor) { "use strict"; function cons() { var result = constructor.apply(this, arguments); result.proto = cons.prototype; return result; } cons.prototype = Object.create(constructor.prototype); return cons; }

  2. Mike Shaver at esdiscuss/2011-March/013154 Function.prototype.createDelegatingTo = function (obj) { var o = new this; // really new-with-apply(arguments) here o.proto = obj; return o; }

Could one of these (or another solution if these do not meet some expectations) be in a strawman and have a chance to ship on ES.next? With Maps and Sets, people will want to extend the prototype of these and come across the exact same issues than usual when it comes to extending the prototype. Having a native and standard way to subclass them would be beneficial for all in my opinion.

Thanks,

David

[1] esdiscuss/2011-March/013131

# Allen Wirfs-Brock (14 years ago)

On Jun 13, 2011, at 3:46 PM, David Bruant wrote:

Hi,

The subclassing native constructor issue came out several times on the list and on the web. However, I do not see a strawman for this. There are strawman:array_create and strawman:array_subtypes, but no mention of a generic solution.

The <| operator is the proposed solution.

Using <| instances with arbitrary [[Prototype]] values can be created for any type built-in object type that has a literal representation. that is functions, arrays, regexps, and less interestingly, strings, numbers, booleans. The resulting instance all have the appropriate special internal behaviors that are associated with the built-in types.

# David Bruant (14 years ago)

Le 14/06/2011 01:24, Allen Wirfs-Brock a écrit :

On Jun 13, 2011, at 3:46 PM, David Bruant wrote:

Hi,

The subclassing native constructor issue came out several times on the list and on the web. However, I do not see a strawman for this. There are strawman:array_create and strawman:array_subtypes, but no mention of a generic solution. The <| operator is the proposed solution.

Oh ok, sorry, I hadn't read it yet. Thanks.

Using <| instances with arbitrary [[Prototype]] values can be created for any type built-in object type that has a literal representation. that is functions, arrays, regexps, and less interestingly, strings, numbers, booleans. The resulting instance all have the appropriate special internal behaviors that are associated with the built-in types.

It requires the right-hand side to have a specific initialization syntax. It currently works for all the "classes" you cited ("functions, arrays, regexps, and less interestingly, strings, numbers, booleans"), but does not for the current harmony:simple_maps_and_sets for which there is currently no specific syntax. Consequently, these could not be subclassed (or I am missing something). This would be the case for any other native "class" that wouldn't such syntax. I'm not sure it's is viable in the long term because it will require all subclassable (something people will want to subclass) "classes" to have a syntax.

I like the idea of the <| operator, but a generic non-syntaxy solution would be good too in my opinion. It would also allow people to subclass host constructors (host objects with [[Construct]]).

# Mark S. Miller (14 years ago)

On Mon, Jun 13, 2011 at 5:08 PM, David Bruant <david.bruant at labri.fr> wrote:

Le 14/06/2011 01:24, Allen Wirfs-Brock a écrit :

On Jun 13, 2011, at 3:46 PM, David Bruant wrote:

Hi,

The subclassing native constructor issue came out several times on the list and on the web. However, I do not see a strawman for this. There are strawman:array_create and strawman:array_subtypes, but no mention of a generic solution. The <| operator is the proposed solution. Oh ok, sorry, I hadn't read it yet. Thanks.

Using <| instances with arbitrary [[Prototype]] values can be created for any type built-in object type that has a literal representation. that is functions, arrays, regexps, and less interestingly, strings, numbers, booleans. The resulting instance all have the appropriate special internal behaviors that are associated with the built-in types. It requires the right-hand side to have a specific initialization syntax. It currently works for all the "classes" you cited ("functions, arrays, regexps, and less interestingly, strings, numbers, booleans"), but does not for the current harmony:simple_maps_and_sets for which there is currently no specific syntax. Consequently, these could not be subclassed (or I am missing something). This would be the case for any other native "class" that wouldn't such syntax. I'm not sure it's is viable in the long term because it will require all subclassable (something people will want to subclass) "classes" to have a syntax.

I like the idea of the <| operator, but a generic non-syntaxy solution would be good too in my opinion. It would also allow people to subclass host constructors (host objects with [[Construct]]).

We have noticed this issue, and an draft of the classes proposal attempted to address it. What's left of that, at < harmony:classes#constructor_chaining>

is:

These semantics for constructor chaining preclude defining classes that inherit from various distinguished built-in constructors, such as Date, Array, RegExp, Function, Error, etc, whose [[Construct]] ignores the normal object passed in as the this-binding and instead creates a fresh specialized object. Similar problems occur for DOM constructors such as HTMLElement. This strawman can be extended to handle such cases, but probably at the cost of making classes something more than syntactic sugar for functions. We leave that to other strawmen to explore. I continue to believe that it would be valuable to subclass built-ins, that classes are a fine place to hang this on, and that it should be developed as a separate strawman proposing to extend classes in this way. The "something more than syntactic sugar" may be a big impediment to adoption of such a strawman, and should rule it out for ES-next. Is there some simple limitation we could impose on classes in the ES-next timeframe to avoid painting ourselves into a corner, such that we could still consider such a strawman for ES-after-next?

# Allen Wirfs-Brock (14 years ago)

At a meta-level, I think we meed to be careful of our terminology here.

What <| does is create an instance of its RHS that is in all ways identical to the original RHS except for the values of its [[Prototype]] internal property. This includes internal properties such as [[Class]]. For example, myProto <| [1,2,3], creates an object that still has a [[Class]] value of "Array". I don't think it is particularly accurate to think of this object as being an instance of a "subclass" of Array. The <| proposal suggests that <| should be called "prototype for". If we are going to have an explicit class declaration, I think we should reserve the term "subclass" for the specialization semantics defined by that construct.

On Jun 13, 2011, at 5:08 PM, David Bruant wrote:

Le 14/06/2011 01:24, Allen Wirfs-Brock a écrit :

On Jun 13, 2011, at 3:46 PM, David Bruant wrote:

Hi,

The subclassing native constructor issue came out several times on the list and on the web. However, I do not see a strawman for this. There are strawman:array_create and strawman:array_subtypes, but no mention of a generic solution. The <| operator is the proposed solution. Oh ok, sorry, I hadn't read it yet. Thanks.

Using <| instances with arbitrary [[Prototype]] values can be created for any type built-in object type that has a literal representation. that is functions, arrays, regexps, and less interestingly, strings, numbers, booleans. The resulting instance all have the appropriate special internal behaviors that are associated with the built-in types. It requires the right-hand side to have a specific initialization syntax. It currently works for all the "classes" you cited ("functions, arrays, regexps, and less interestingly, strings, numbers, booleans"),

I'd be very careful about using the term "classes" to describe these kinds of built-on objects. There distinguishing characteristics are all extra-lingual behaviors that can't be specified via the class declarations as currently proposed.

but does not for the current harmony:simple_maps_and_sets for which there is currently no specific syntax.

Good point.

If the current specification of Map and Set in the proposal is taken as normative then they can be subclassed simply by: class MyMap extends Map { constructor () {super()} }

This should work because there is nothing in the definition of Map that depends upon any new or modified [[ ]] internal behaviors or state. This would still be true even if get/has/set/delete have native implementations which they undoubtably would in order to avoid linear lookup. There only real dependency is upon the private instance variables keys and vals and the proposed subclassing mechanism would handle that.

Consequently, these could not be subclassed (or I am missing something). This would be the case for any other native "class" that wouldn't such syntax. I'm not sure it's is viable in the long term because it will require all subclassable (something people will want to subclass) "classes" to have a syntax.

I like the idea of the <| operator, but a generic non-syntaxy solution would be good too in my opinion. It would also allow people to subclass host constructors (host objects with [[Construct]]).

As currently specified it isn't really possible to say what would or wouldn't work with host objects. For example, host object aren't even required to may attention to the value of [[Prototype]]. The bigger issue that is lurking is what does it mean to subclass a Proxy. They are the ES.next equivalent of host objects.

# David Bruant (14 years ago)

Le 14/06/2011 07:04, Mark S. Miller a écrit :

On Mon, Jun 13, 2011 at 5:08 PM, David Bruant <david.bruant at labri.fr <mailto:david.bruant at labri.fr>> wrote:

Le 14/06/2011 01:24, Allen Wirfs-Brock a écrit :
> On Jun 13, 2011, at 3:46 PM, David Bruant wrote:
>> Hi,
>>
>> The subclassing native constructor issue came out several times
on the
>> list and on the web. However, I do not see a strawman for this.
There
>> are strawman:array_create and strawman:array_subtypes, but no
mention of
>> a generic solution.
> The <| operator is the proposed solution.
Oh ok, sorry, I hadn't read it yet. Thanks.

> Using <|  instances with arbitrary [[Prototype]] values can be
created for any type built-in object type that has a literal
representation.  that is functions, arrays, regexps, and less
interestingly, strings, numbers, booleans.  The resulting instance
all have the appropriate special internal behaviors that are
associated with the built-in types.
It requires the right-hand side to have a specific initialization
syntax. It currently works for all the "classes" you cited
("functions,
arrays, regexps, and less interestingly, strings, numbers, booleans"),
but does not for the current harmony:simple_maps_and_sets for which
there is currently no specific syntax. Consequently, these could
not be
subclassed (or I am missing something).
This would be the case for any other native "class" that wouldn't such
syntax. I'm not sure it's is viable in the long term because it will
require all subclassable (something people will want to subclass)
"classes" to have a syntax.

I like the idea of the <| operator, but a generic non-syntaxy solution
would be good too in my opinion. It would also allow people to
subclass
host constructors (host objects with [[Construct]]).

We have noticed this issue, and an draft of the classes proposal attempted to address it. What's left of that, at harmony:classes#constructor_chaining is:

These semantics for constructor chaining preclude defining classes that inherit from various distinguished built-in constructors, such as Date, Array, RegExp, Function, Error, etc, whose |[[Construct]]| ignores the normal object passed in as the this-binding and instead creates a fresh specialized object. Similar problems occur for DOM constructors such as HTMLElement. This strawman can be extended to handle such cases, but probably at the cost of making classes something more than syntactic sugar for functions. We leave that to other strawmen to explore.

I think that saying "whose [[Construct]] ignores the normal object passed in as the this-binding and instead creates a fresh specialized object." is misleading. It seems to imply that the internal [[Construct]] method of an object always create a "normal object". It is not true. Internal [[Construct]] of native functions (ES5 - 13.2.2) create a normal object (step 1), but there is no constraints for other objects with an internal [[Construct]] to do so. Namely, Date, Array, RegExp, Function, Error have a different approach to [[Construct]]. Host objects aren't This difference is further emphasis with Harmony proxies which have the ability to provide two completely different functions to Proxy.createFunction(handler, call, construct).

By the way, slightly above the paragraph you quote is written: "Within the body of the constructor, an expression super(x, y) calls the superclass's [[Call]] method with thisArg bound to this constructor's this and the arguments x and y." Why has [[Call]] been chosen over [[Construct]]? The latter makes much more sense in the context of inheritance in my opinion. And if I ask "A extend B" and B is a function proxy for which I have provided a custom [[Construct]], I expect this one to be called, not [[Call]].

I continue to believe that it would be valuable to subclass built-ins, that classes are a fine place to hang this on, and that it should be developed as a separate strawman proposing to extend classes in this way. The "something more than syntactic sugar" may be a big impediment to adoption of such a strawman, and should rule it out for ES-next. Is there some simple limitation we could impose on classes in the ES-next timeframe to avoid painting ourselves into a corner, such that we could still consider such a strawman for ES-after-next?

Actually, I think that if what I've said above is considered, built-in classes won't be precluded anymore. And the following code would be legit:

class SortedArray extends Array{ constructor(args){ return super(...args); // call Array's [[Construct]] }

indexOf(e){ // I can do an efficient binary search, because it maintain the invariant that my array is sorted }

push(e){ // Changing push def, because I have to maintain the array sorted. }

// ... // .forEach, .filter and other awesome functions are inherited from Array.prototype }

var sa = new SortedArray(); // sa -> SortedArray.prototype -> Array.prototype -> Object.prototype ->

null // sa is a native Array object thanks to the "super" call in SortedArray constructor.

# David Bruant (14 years ago)

Le 14/06/2011 18:30, Allen Wirfs-Brock a écrit :

At a meta-level, I think we meed to be careful of our terminology here.

What<| does is create an instance of its RHS that is in all ways identical to the original RHS except for the values of its [[Prototype]] internal property. This includes internal properties such as [[Class]]. For example, myProto<| [1,2,3], creates an object that still has a [[Class]] value of "Array". I don't think it is particularly accurate to think of this object as being an instance of a "subclass" of Array. The<| proposal suggests that<| should be called "prototype for". If we are going to have an explicit class declaration, I think we should reserve the term "subclass" for the specialization semantics defined by that construct.

You're right, I've been a little light on my terminology.

On Jun 13, 2011, at 5:08 PM, David Bruant wrote:

but does not for the current harmony:simple_maps_and_sets for which there is currently no specific syntax. Good point.

If the current specification of Map and Set in the proposal is taken as normative then they can be subclassed simply by: class MyMap extends Map { constructor () {super()} }

This should work because there is nothing in the definition of Map that depends upon any new or modified [[ ]] internal behaviors or state. This would still be true even if get/has/set/delete have native implementations which they undoubtably would in order to avoid linear lookup. There only real dependency is upon the private instance variables keys and vals and the proposed subclassing mechanism would handle that.

I think I am missing something. Why are objects with modified internal [[]] methods forbidden with class inheritance mechanism?

Consequently, these could not be subclassed (or I am missing something). This would be the case for any other native "class" that wouldn't such syntax. I'm not sure it's is viable in the long term because it will require all subclassable (something people will want to subclass) "classes" to have a syntax.

I like the idea of the<| operator, but a generic non-syntaxy solution would be good too in my opinion. It would also allow people to subclass host constructors (host objects with [[Construct]]). As currently specified it isn't really possible to say what would or wouldn't work with host objects. For example, host object aren't even required to may attention to the value of [[Prototype]]. The bigger issue that is lurking is what does it mean to subclass a Proxy. They are the ES.next equivalent of host objects.

Indeed. Shouldn't a class mechanism capture these (host constructors and function proxies) as well right away or is there a particular urge justifying not doing so by ES.next release?

# Mark S. Miller (14 years ago)

On Wed, Jun 15, 2011 at 7:17 AM, David Bruant <david.bruant at labri.fr> wrote:

** Le 14/06/2011 07:04, Mark S. Miller a écrit :

On Mon, Jun 13, 2011 at 5:08 PM, David Bruant <david.bruant at labri.fr>wrote:

Le 14/06/2011 01:24, Allen Wirfs-Brock a écrit :

On Jun 13, 2011, at 3:46 PM, David Bruant wrote:

Hi,

The subclassing native constructor issue came out several times on the list and on the web. However, I do not see a strawman for this. There are strawman:array_create and strawman:array_subtypes, but no mention of

a generic solution. The <| operator is the proposed solution. Oh ok, sorry, I hadn't read it yet. Thanks.

Using <| instances with arbitrary [[Prototype]] values can be created for any type built-in object type that has a literal representation. that is functions, arrays, regexps, and less interestingly, strings, numbers, booleans. The resulting instance all have the appropriate special internal behaviors that are associated with the built-in types. It requires the right-hand side to have a specific initialization syntax. It currently works for all the "classes" you cited ("functions, arrays, regexps, and less interestingly, strings, numbers, booleans"), but does not for the current harmony:simple_maps_and_sets for which there is currently no specific syntax. Consequently, these could not be subclassed (or I am missing something). This would be the case for any other native "class" that wouldn't such syntax. I'm not sure it's is viable in the long term because it will require all subclassable (something people will want to subclass) "classes" to have a syntax.

I like the idea of the <| operator, but a generic non-syntaxy solution would be good too in my opinion. It would also allow people to subclass host constructors (host objects with [[Construct]]).

We have noticed this issue, and an draft of the classes proposal attempted to address it. What's left of that, at < harmony:classes#constructor_chaining> is:

These semantics for constructor chaining preclude defining classes that inherit from various distinguished built-in constructors, such as Date, Array, RegExp, Function, Error, etc, whose [[Construct]] ignores the normal object passed in as the this-binding and instead creates a fresh specialized object. Similar problems occur for DOM constructors such as HTMLElement. This strawman can be extended to handle such cases, but probably at the cost of making classes something more than syntactic sugar for functions. We leave that to other strawmen to explore.

I think that saying "whose [[Construct]] ignores the normal object passed in as the this-binding and instead creates a fresh specialized object." is misleading. It seems to imply that the internal [[Construct]] method of an object always create a "normal object". It is not true. Internal [[Construct]] of native functions (ES5 - 13.2.2) create a normal object (step 1), but there is no constraints for other objects with an internal [[Construct]] to do so. Namely, Date, Array, RegExp, Function, Error have a different approach to [[Construct]]. Host objects aren't This difference is further emphasis with Harmony proxies which have the ability to provide two completely different functions to Proxy.createFunction(handler, call, construct).

By the way, slightly above the paragraph you quote is written: "Within the body of the constructor, an expression super(x, y) calls the superclass’s [[Call]] method with thisArg bound to this constructor’s this and the arguments x and y." Why has [[Call]] been chosen over [[Construct]]? The latter makes much more sense in the context of inheritance in my opinion. And if I ask "A extend B" and B is a function proxy for which I have provided a custom [[Construct]], I expect this one to be called, not [[Call]].

As [[Construct]] is currently defined, you can't pass in an already constructed object for it to further initialize. So it doesn't make sense for constructor chaining to call the superclass' [[Construct]], even if the superclass is a function proxy.

# David Bruant (14 years ago)

Le 15/06/2011 16:43, Mark S. Miller a écrit :

On Wed, Jun 15, 2011 at 7:17 AM, David Bruant <david.bruant at labri.fr <mailto:david.bruant at labri.fr>> wrote:

Le 14/06/2011 07:04, Mark S. Miller a écrit :
On Mon, Jun 13, 2011 at 5:08 PM, David Bruant
<david.bruant at labri.fr <mailto:david.bruant at labri.fr>> wrote:

    Le 14/06/2011 01:24, Allen Wirfs-Brock a écrit :
    > On Jun 13, 2011, at 3:46 PM, David Bruant wrote:
    >> Hi,
    >>
    >> The subclassing native constructor issue came out several
    times on the
    >> list and on the web. However, I do not see a strawman for
    this. There
    >> are strawman:array_create and strawman:array_subtypes, but
    no mention of
    >> a generic solution.
    > The <| operator is the proposed solution.
    Oh ok, sorry, I hadn't read it yet. Thanks.

    > Using <|  instances with arbitrary [[Prototype]] values can
    be created for any type built-in object type that has a
    literal representation.  that is functions, arrays, regexps,
    and less interestingly, strings, numbers, booleans.  The
    resulting instance all have the appropriate special internal
    behaviors that are associated with the built-in types.
    It requires the right-hand side to have a specific initialization
    syntax. It currently works for all the "classes" you cited
    ("functions,
    arrays, regexps, and less interestingly, strings, numbers,
    booleans"),
    but does not for the current harmony:simple_maps_and_sets for
    which
    there is currently no specific syntax. Consequently, these
    could not be
    subclassed (or I am missing something).
    This would be the case for any other native "class" that
    wouldn't such
    syntax. I'm not sure it's is viable in the long term because
    it will
    require all subclassable (something people will want to subclass)
    "classes" to have a syntax.

    I like the idea of the <| operator, but a generic non-syntaxy
    solution
    would be good too in my opinion. It would also allow people
    to subclass
    host constructors (host objects with [[Construct]]).


We have noticed this issue, and an draft of the classes proposal
attempted to address it. What's left of that, at
<http://wiki.ecmascript.org/doku.php?id=harmony:classes#constructor_chaining>
is:

These semantics for constructor chaining preclude defining
classes that inherit from various distinguished built-in
constructors, such as Date, Array, RegExp, Function, Error, etc,
whose |[[Construct]]| ignores the normal object passed in as the
this-binding and instead creates a fresh specialized object.
Similar problems occur for DOM constructors such as HTMLElement.
This strawman can be extended to handle such cases, but probably
at the cost of making classes something more than syntactic sugar
for functions. We leave that to other strawmen to explore.
I think that saying "whose [[Construct]] ignores the normal object
passed in as the this-binding and instead creates a fresh
specialized object." is misleading. It seems to imply that the
internal [[Construct]] method of an object always create a "normal
object". It is not true. Internal [[Construct]] of native
functions (ES5 - 13.2.2) create a normal object (step 1), but
there is no constraints for other objects with an internal
[[Construct]] to do so.
Namely, Date, Array, RegExp, Function, Error have a different
approach to [[Construct]]. Host objects aren't This difference is
further emphasis with Harmony proxies which have the ability to
provide two completely different functions to
Proxy.createFunction(handler, call, construct).

By the way, slightly above the paragraph you quote is written:
"Within the body of the constructor, an expression super(x, y)
calls the superclass’s [[Call]] method with thisArg bound to this
constructor’s this and the arguments x and y."
Why has [[Call]] been chosen over [[Construct]]? The latter makes
much more sense in the context of inheritance in my opinion. And
if I ask "A extend B" and B is a function proxy for which I have
provided a custom [[Construct]], I expect this one to be called,
not [[Call]].

As [[Construct]] is currently defined, you can't pass in an already constructed object for it to further initialize. So it doesn't make sense for constructor chaining to call the superclass' [[Construct]], even if the superclass is a function proxy.

Hmm... I think that it's because most current [[Construct]] (ES5 - 13.2.2) have steps 1 and 9-10. As far as I know, on ES5, [[Construct]] is only used in the "new" operator; Would it make sense to move steps 1, 9 & 10 to the "new" operator definition (ES5 - 11.2.2)? The object would be passed as the 'this' binding of [[Construct]]. It would allow to create different objects on step 1 depending on context (for instance if the constructor has been created in a "class"-syntax defintion, the object may inherit from something else than Object.prototype). I don't think it would affect how the "new" operator currently works.

Now that I think about it, there is a weird difference between [[Call]] and [[Construct]]. The former has a 'this' binding and the latter doesn't. Considering the object being constructed as a 'this' binding to [[Construct]] could allow what you said ("pass in an already constructed object for it to further initialize") by passing the same 'this' object to several [[Construct]].

Does this change sounds feasable?

Regardless of this change, I think I understand that there is some issue with wanting a class syntax and inheriting from built-in/host constructors. Not because of [[Construct]], but because of the custom Meta Object Programming contract.

# Mark S. Miller (14 years ago)

On Wed, Jun 15, 2011 at 8:17 AM, David Bruant <david.bruant at labri.fr> wrote:

** Le 15/06/2011 16:43, Mark S. Miller a écrit :

On Wed, Jun 15, 2011 at 7:17 AM, David Bruant <david.bruant at labri.fr>wrote:

Le 14/06/2011 07:04, Mark S. Miller a écrit :

On Mon, Jun 13, 2011 at 5:08 PM, David Bruant <david.bruant at labri.fr>wrote:

Le 14/06/2011 01:24, Allen Wirfs-Brock a écrit :

On Jun 13, 2011, at 3:46 PM, David Bruant wrote:

Hi,

The subclassing native constructor issue came out several times on the list and on the web. However, I do not see a strawman for this. There are strawman:array_create and strawman:array_subtypes, but no mention of

a generic solution. The <| operator is the proposed solution. Oh ok, sorry, I hadn't read it yet. Thanks.

Using <| instances with arbitrary [[Prototype]] values can be created for any type built-in object type that has a literal representation. that is functions, arrays, regexps, and less interestingly, strings, numbers, booleans. The resulting instance all have the appropriate special internal behaviors that are associated with the built-in types. It requires the right-hand side to have a specific initialization syntax. It currently works for all the "classes" you cited ("functions, arrays, regexps, and less interestingly, strings, numbers, booleans"), but does not for the current harmony:simple_maps_and_sets for which there is currently no specific syntax. Consequently, these could not be subclassed (or I am missing something). This would be the case for any other native "class" that wouldn't such syntax. I'm not sure it's is viable in the long term because it will require all subclassable (something people will want to subclass) "classes" to have a syntax.

I like the idea of the <| operator, but a generic non-syntaxy solution would be good too in my opinion. It would also allow people to subclass host constructors (host objects with [[Construct]]).

We have noticed this issue, and an draft of the classes proposal attempted to address it. What's left of that, at < harmony:classes#constructor_chaining> is:

These semantics for constructor chaining preclude defining classes that inherit from various distinguished built-in constructors, such as Date, Array, RegExp, Function, Error, etc, whose [[Construct]] ignores the normal object passed in as the this-binding and instead creates a fresh specialized object. Similar problems occur for DOM constructors such as HTMLElement. This strawman can be extended to handle such cases, but probably at the cost of making classes something more than syntactic sugar for functions. We leave that to other strawmen to explore.

I think that saying "whose [[Construct]] ignores the normal object passed in as the this-binding and instead creates a fresh specialized object." is misleading. It seems to imply that the internal [[Construct]] method of an object always create a "normal object". It is not true. Internal [[Construct]] of native functions (ES5 - 13.2.2) create a normal object (step 1), but there is no constraints for other objects with an internal [[Construct]] to do so. Namely, Date, Array, RegExp, Function, Error have a different approach to [[Construct]]. Host objects aren't This difference is further emphasis with Harmony proxies which have the ability to provide two completely different functions to Proxy.createFunction(handler, call, construct).

By the way, slightly above the paragraph you quote is written: "Within the body of the constructor, an expression super(x, y) calls the superclass’s [[Call]] method with thisArg bound to this constructor’s this and the arguments x and y." Why has [[Call]] been chosen over [[Construct]]? The latter makes much more sense in the context of inheritance in my opinion. And if I ask "A extend B" and B is a function proxy for which I have provided a custom [[Construct]], I expect this one to be called, not [[Call]].

As [[Construct]] is currently defined, you can't pass in an already constructed object for it to further initialize. So it doesn't make sense for constructor chaining to call the superclass' [[Construct]], even if the superclass is a function proxy.

Hmm... I think that it's because most current [[Construct]] (ES5 - 13.2.2) have steps 1 and 9-10. As far as I know, on ES5, [[Construct]] is only used in the "new" operator; Would it make sense to move steps 1, 9 & 10 to the "new" operator definition (ES5 - 11.2.2)? The object would be passed as the 'this' binding of [[Construct]]. It would allow to create different objects on step 1 depending on context (for instance if the constructor has been created in a "class"-syntax defintion, the object may inherit from something else than Object.prototype). I don't think it would affect how the "new" operator currently works.

Now that I think about it, there is a weird difference between [[Call]] and [[Construct]]. The former has a 'this' binding and the latter doesn't. Considering the object being constructed as a 'this' binding to [[Construct]] could allow what you said ("pass in an already constructed object for it to further initialize") by passing the same 'this' object to several [[Construct]].

Does this change sounds feasable?

I think some such refactoring would be feasible and desirable, and is the kind of refactoring I had in mind when I said

This strawman can be extended to handle such cases, but probably at the cost of making classes something more than syntactic sugar for functions. We leave that to other strawmen to explore.

But the refactoring would need to be a bit different than what you suggest, in order to both maintain compat with current behavior while also allowing subclassing-with-constructor-chaining to, for example, Date. Please propose something.

# David Bruant (14 years ago)

Le 15/06/2011 18:11, Mark S. Miller a écrit :

On Wed, Jun 15, 2011 at 8:17 AM, David Bruant <david.bruant at labri.fr <mailto:david.bruant at labri.fr>> wrote:

Le 15/06/2011 16:43, Mark S. Miller a écrit :
On Wed, Jun 15, 2011 at 7:17 AM, David Bruant
<david.bruant at labri.fr <mailto:david.bruant at labri.fr>> wrote:

    Le 14/06/2011 07:04, Mark S. Miller a écrit :
    On Mon, Jun 13, 2011 at 5:08 PM, David Bruant
    <david.bruant at labri.fr <mailto:david.bruant at labri.fr>> wrote:

        Le 14/06/2011 01:24, Allen Wirfs-Brock a écrit :
        > On Jun 13, 2011, at 3:46 PM, David Bruant wrote:
        >> Hi,
        >>
        >> The subclassing native constructor issue came out
        several times on the
        >> list and on the web. However, I do not see a strawman
        for this. There
        >> are strawman:array_create and
        strawman:array_subtypes, but no mention of
        >> a generic solution.
        > The <| operator is the proposed solution.
        Oh ok, sorry, I hadn't read it yet. Thanks.

        > Using <|  instances with arbitrary [[Prototype]]
        values can be created for any type built-in object type
        that has a literal representation.  that is functions,
        arrays, regexps, and less interestingly, strings,
        numbers, booleans.  The resulting instance all have the
        appropriate special internal behaviors that are
        associated with the built-in types.
        It requires the right-hand side to have a specific
        initialization
        syntax. It currently works for all the "classes" you
        cited ("functions,
        arrays, regexps, and less interestingly, strings,
        numbers, booleans"),
        but does not for the current
        harmony:simple_maps_and_sets for which
        there is currently no specific syntax. Consequently,
        these could not be
        subclassed (or I am missing something).
        This would be the case for any other native "class" that
        wouldn't such
        syntax. I'm not sure it's is viable in the long term
        because it will
        require all subclassable (something people will want to
        subclass)
        "classes" to have a syntax.

        I like the idea of the <| operator, but a generic
        non-syntaxy solution
        would be good too in my opinion. It would also allow
        people to subclass
        host constructors (host objects with [[Construct]]).


    We have noticed this issue, and an draft of the classes
    proposal attempted to address it. What's left of that, at
    <http://wiki.ecmascript.org/doku.php?id=harmony:classes#constructor_chaining>
    is:

    These semantics for constructor chaining preclude defining
    classes that inherit from various distinguished built-in
    constructors, such as Date, Array, RegExp, Function, Error,
    etc, whose |[[Construct]]| ignores the normal object passed
    in as the this-binding and instead creates a fresh
    specialized object. Similar problems occur
    for DOM constructors such as HTMLElement. This strawman can
    be extended to handle such cases, but probably at the cost
    of making classes something more than syntactic sugar for
    functions. We leave that to other strawmen to explore.
    I think that saying "whose [[Construct]] ignores the normal
    object passed in as the this-binding and instead creates a
    fresh specialized object." is misleading. It seems to imply
    that the internal [[Construct]] method of an object always
    create a "normal object". It is not true. Internal
    [[Construct]] of native functions (ES5 - 13.2.2) create a
    normal object (step 1), but there is no constraints for other
    objects with an internal [[Construct]] to do so.
    Namely, Date, Array, RegExp, Function, Error have a different
    approach to [[Construct]]. Host objects aren't This
    difference is further emphasis with Harmony proxies which
    have the ability to provide two completely different
    functions to Proxy.createFunction(handler, call, construct).

    By the way, slightly above the paragraph you quote is written:
    "Within the body of the constructor, an expression super(x,
    y) calls the superclass’s [[Call]] method with thisArg bound
    to this constructor’s this and the arguments x and y."
    Why has [[Call]] been chosen over [[Construct]]? The latter
    makes much more sense in the context of inheritance in my
    opinion. And if I ask "A extend B" and B is a function proxy
    for which I have provided a custom [[Construct]], I expect
    this one to be called, not [[Call]].


As [[Construct]] is currently defined, you can't pass in an
already constructed object for it to further initialize. So it
doesn't make sense for constructor chaining to call the
superclass' [[Construct]], even if the superclass is a function
proxy.
Hmm... I think that it's because most current [[Construct]] (ES5 -
13.2.2) have steps 1 and 9-10. As far as I know, on ES5,
[[Construct]] is only used in the "new" operator; Would it make
sense to move steps 1, 9 & 10 to the "new" operator definition
(ES5 - 11.2.2)? The object would be passed as the 'this' binding
of [[Construct]]. It would allow to create different objects on
step 1 depending on context (for instance if the constructor has
been created in a "class"-syntax defintion, the object may inherit
from something else than Object.prototype). I don't think it would
affect how the "new" operator currently works.

Now that I think about it, there is a weird difference between
[[Call]] and [[Construct]]. The former has a 'this' binding and
the latter doesn't. Considering the object being constructed as a
'this' binding to [[Construct]] could allow what you said ("pass
in an already constructed object for it to further initialize") by
passing the same 'this' object to several [[Construct]].

Does this change sounds feasable?

I think some such refactoring would be feasible and desirable, and is the kind of refactoring I had in mind when I said

This strawman can be extended to handle such cases, but probably
at the cost of making classes something more than syntactic sugar
for functions. We leave that to other strawmen to explore.

But the refactoring would need to be a bit different than what you suggest, in order to both maintain compat with current behavior while also allowing subclassing-with-constructor-chaining to, for example, Date. Please propose something.

I may be missing something but I have the impression that what I've suggested works with Date too. In the way I see it, Date.[[Construct]] is defined in ES5 - 15.9.3.{1,2,3}. In what I suggested, "new Date();" would create an object (ES5 - 13.2.2 step1 moved to "new" operator), Date.[[Construct]] would be called, return what is said on ES5 - 15.9.3.{1,2,3}, which is an object and step9 (of ES5 - 13.2.2 moved to "new" operator) would notice it, and forget about the object created on step1 (implementations are free to optimize here) and return the correct object. I'm not a specialist of Dates. Do they have some specificity I am missing in my explanation?

I don't know if it's the same issue, but I see a problem with trying to subclass built-in constructor which create objects with a different meta-object programming contract than the native object one. Let's consider for a minute that an object is: [[MOP]] + [[Prototype]] (looks like Proxy.create signature ;-)). [[Prototype]] being itself an object ([[MOP]] + [[Prototype]]) or null. Wanting to subclass arrays is wanting to have the array [[MOP]] with a different [[Prototype]]. Currently, all constructors impose both at the same time. The current class proposal allow to create a constructor for which one can choose the [[Prototype]] (both "extends" and "prototype" allow that). But nothing is said about the [[MOP]].

class A(){constructor(){...}} class B extends A(){constructor(){... super(); ...}} var b = new B(); // on initialization, an object needs to be created. // b.[[Prototype]] is B.prototype (which inherits from A.prototype...) // However, at the time of the call to "new B();", the engine has to decide which [[MOP]] to use. // The object with this [[MOP]] will be used as the 'this' value in B.prototype.constructor and // consequently the [[MOP]] needs to be decided before entering B.prototype.constructor code. // Without other inidication, it has to be arbitrarily the native object [[MOP]] (ES5 - 8.12.{1-9}) // Consequently, there are currently no way to provide another [[MOP]] with current syntax

I do not really know to which extent this is possible, but the same way we declare a [[Prototype]], could we declare a [[MOP]] to be used all along in the different constructors chaining? By providing a handler object? By providing an object from which a [[MOP]] will be extracted?