# Why 2 different default constructors?

**URL:** <https://es.discourse.group/t/why-2-different-default-constructors/180>\
**Category:** I have questions\
**Created:** [January 6, 2020, 1:24am UTC](https://es.discourse.group/t/why-2-different-default-constructors/180 "2020-01-06T01:24:52Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 6, 2020, 1:24am UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/1 "2020-01-06T01:24:52Z")

</div>

Why was `class` designed to need 2 different default constructors? It seems like it would've made things cleaner for there to never be a `[[ConstructorKind]]` , for all actions to happen as if "derived" were the only kind, for the class base to always be either `Object` , `null` , or user specified, and for `super()` to be an internal function that automatically handles the special case of a `null` base. So why split the situation into something that requires 2 different constructor types?

As for wanting to remove the need to call `super()`, that could still be handled fairly easily without needing to manage 2 different forms for the default constructor.

---

<div class="post-metadata">

**Author:** ![claudepache](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudepache/32/236_2.png) [@claudepache](https://es.discourse.group/u/claudepache)\
**Post date:** [January 6, 2020, 11:24am UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/2 "2020-01-06T11:24:03Z")

</div>

> [@rdking](#):
>
> As for wanting to remove the need to call `super()` , that could still be handled fairly easily without needing to manage 2 different forms for the default constructor.

Can you elaborate on how you would handle that in a cleaner way than just having an internal slot like `[[ConstructorKind]]` with two possible values?

Indeed, the need to call `super()` is precisely _the_ difference between derived and base constructors that matters. The rest is just technicalities that most users should ignore unless/until they do something very special with prototype chains.

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 6, 2020, 3:52pm UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/3 "2020-01-06T15:52:08Z")

</div>

> [@claudepache](#):
>
> Can you elaborate on how you would handle that in a cleaner way than just having an internal slot like `[[ConstructorKind]]` with two possible values?

There's more to it than just having `[[ConstructorKind]]`. There's also the need to emit one of 2 different constructors in accordance with that kind, the tracking of the association between `super` and the parent constructor, etc... There's a lot of moving parts. However, if you look at 14.6.13 step 5 & 6.e, you see that there is always a need to track the parent constructor, even if it's specified `extends null`, or not at all.

Given that, first eliminate the "not at all" case by re-spelling it as `extends Object` explicitly when its not specified. This is almost identical to what is currently done except that the "not at all" case does something pointlessly special here by setting the `[[ConstructorKind]]` to "base" and forcing the emission of a `super()`-less constructor. This leaves `extends null` as the only special case.

Since step 6.e.ii prescribes that for this last case, the constructorParent is `%FunctionPrototype%`, there's always a function for `super()` to call. The only problem is that `%FunctionPrototype%` doesn't have a `[[Construct]]`. This is where `super` gets modified. If `super` were instead an internal function with this kind of behavior, the problem would be solved for all cases.

1. Let _envRec_ be GetThisEnvironment().
2. Assert: _envRec_ is a function Environment Record.
3. Let _activeFunction_ be _envRec_.[[FunctionObject]].
4. Assert: _activeFunction_ is an ECMAScript function object.
5. Let _superConstructor_ be ! _activeFunction_.[[GetPrototypeOf]]().
6. If _superConstructor_ is _%FunctionPrototype%_ then  
a. Let _retval_ be an new ECMAScript Object instance.  
b. Let _retval_.[[Prototype]] be null.  
c. Return _retval_.
7. Else if IsConstructor(_superConstructor_) is false, throw a TypeError exception.
8. Return ! _superConstructor_().

Notice that this is only a little more than what `GetSuperConstructor` already does. The only thing left to tidy up is the pesky determination of whether or not `super()` is required in user-defined constructors, but that's easy. Just check to see if `_superConstructor_` is not `_%Object%_` and `_superConstructor_.prototype` is an ECMAScript Object. If this is true, then require super, otherwise don't.

* * *

A bit wordy to be sure, but this get's rid of the null problem for classes and private fields, gets rid of the need to use `super` even for explicit cases of `extends Object` (which never made any sense anyway), reduces slot usage, and gets rid of the need to have 2 default constructors based on whether or not there is an `extends` clause in the _ClassHeritage_.

What do you think?

---

<div class="post-metadata">

**Author:** ![claudiameadows](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudiameadows/32/126_2.png) [@claudiameadows](https://es.discourse.group/u/claudiameadows)\
**Post date:** [January 6, 2020, 7:26pm UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/4 "2020-01-06T19:26:04Z")

</div>

I will note that `super` does mutate the `this` value (and is the only construct that can do it). And it's by design that you can call it in arrow functions.

Quick question: if you remove `super`, how do you plan to address passing parameters to the parent constructor? (This is a very common need among `Promise` subclasses, for instance.)

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 7, 2020, 1:57pm UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/5 "2020-01-07T13:57:35Z")

</div>

> [@claudiameadows](#):
>
> Quick question: if you remove `super` , how do you plan to address passing parameters to the parent constructor?

My original comment about "wanting to remove the need to call `super()` " was in reference to the dual-default constructor situation. One of them has `super()` , the other doesn't. Presumably, this exists because there was a desire to allow a base class constructor to work without needing to call `super()` while requiring it for derived classes. My goal is to remove the need for dual-default constructors, keeping only the one that contains `super()` , and modifying `super()` so that it does something appropriate for the `extends null` case.

As a side goal, I also want `class X` and `class X extends Object` to be equivalent. Initializing the base class is always necessary (even if no parameters are involved), so there's no way to get rid of `super()` . Nor would I do so even if there was. I just wish TC39 had've chosen an approach that's less Java-like. Having `super` be both a constructor and a prototype reference with pseudo- `this` -bound methods is just a little to special for my taste, but that's a moot point now.

---

<div class="post-metadata">

**Author:** ![claudepache](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudepache/32/236_2.png) [@claudepache](https://es.discourse.group/u/claudepache)\
**Post date:** [January 7, 2020, 2:41pm UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/6 "2020-01-07T14:41:40Z")

</div>

I was wrong when I said:

> [@claudepache](#):
>
> Indeed, the need to call `super()` is precisely _the_ difference between derived and base constructors that matters.

In fact, there is no need to call super(), ever, since you can return a custom object instead of using the default one set to the `this`-binding.

The true difference between derived and base constructors is: whether an object of the appropriate type is initialised (and assigned to the `this`-binding) before the body of the constructor is interpreted.

* * *

The design process of the `class` construct has been long and bumpy, with trials-and-errors. The final design, which is indeed not conceptually the simplest one, satisfies several constraints that were difficult to reconcile:

- It grandfathers the prehistoric way to define constructors, namely as: `function Foo(x) { /* ... */ }; var foo = new Foo(x)`. That is to say, the `new` operator does not change semantics for those constructors, and they may be used as target for the `extends` clause.

- It allows to subclass builtin classes (e.g., `Array`) that don’t behave as plain objects, and that need to be created and initialised in one step.

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 7, 2020, 4:05pm UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/7 "2020-01-07T16:05:55Z")

</div>

> [@claudepache](#):
>
> I was wrong....
> 
> In fact, there is no need to call super(), ever, since you can return a custom object instead of using the default one set to the `this` -binding.

While true enough, it still misses my point. I'm saying there's no need for the class evaluation process to worry over which of 2 different default constructors to use. The suggestions I offered above serve to reduce this down to the default constructor being the version that uses `super()`, completely disregarding the other version. As for the 2 special cases:

- solve the "no `extends` clause" case by treating it as equivalent to `extends Object`, which isn't too different from what currently happens.
- solve the `extends null` case by moving the special handling into `super()` so it simply returns an ECMAScript object with a null `[[Prototype]]` if the base class is `null`.

Do this and there's no longer a need for the default empty constructor.

> [@claudepache](#):
>
> The design process of the `class` construct has been long and bumpy, with trials-and-errors. The final design, which is indeed not conceptually the simplest one, satisfies several constraints that were difficult to reconcile

What's so hard about reconciling the 2 constraint's you listed? They don't conflict and aren't particularly difficult to handle. Keeping step with the "prehistoric" (🤣) way of defining constructors only made since given that all the tools necessary were already there. Subclassing built-in classes was the only moderately tricky part as you have to pass-the-buck of creating the actual instance all the way up the chain to the first ancestor before processing any use of `this`.

So what am I missing, and what does that have to do with the reasoning behind having 2 default constructors?

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [January 7, 2020, 5:26pm UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/8 "2020-01-07T17:26:52Z")

</div>

Are you suggesting that base class constructors should be required to call super() before accessing the receiver?

(obviously this is an academic argument; the differences between base and derived classes won’t/can’t change at this point)

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 7, 2020, 6:53pm UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/9 "2020-01-07T18:53:26Z")

</div>

> [@ljharb](#):
>
> Are you suggesting that base class constructors should be required to call super() before accessing the receiver?

Not if user written. However, there's no particular reason why the default constructor cannot under the conditions I've given.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [January 7, 2020, 8:11pm UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/10 "2020-01-07T20:11:12Z")

</div>

The default constructor needs to be expressible in JS (as it currently is) - how would you achieve that with your suggestion?

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 9, 2020, 4:21am UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/11 "2020-01-09T04:21:53Z")

</div>

> [@ljharb](#):
>
> The default constructor needs to be expressible in JS (as it currently is) - how would you achieve that with your suggestion?

The default constructor would always be expressible in JS. It would be the current derived-type default constructor. What would be different is that `super()` would have extra behavioral semantics to handle the `extends null` case.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [January 9, 2020, 4:43am UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/12 "2020-01-09T04:43:08Z")

</div>

Can you give me a code example of a constructor that uses `this`, conditionally calls `super()` before doing so and according to which conditions, that works for both a base and a derived class?

---

<div class="post-metadata">

**Author:** ![rdking](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/rdking/32/54_2.png) [@rdking](https://es.discourse.group/u/rdking)\
**Post date:** [January 9, 2020, 5:17am UTC](https://es.discourse.group/t/why-2-different-default-constructors/180/13 "2020-01-09T05:17:47Z")

</div>

I'm not sure I understand where you're going with this line of questions. Somehow I think you're misunderstanding something. The changes I described wouldn't alter any of the semantics that a developer will see, excepting the new equivalence of `class X extends Object {}` being the same as `class X`, and `extends null` wouldn't currently be in conflict with private fields. Everything that is currently true about how a developer creates a class would remain the same, including the use of `super()` in the constructor of derived classes and its absence in base classes.
