The `super` keyword doesn't work as it should?
Logan Smyth
loganfsmyth at gmail.com
Tue Jul 19 16:12:20 UTC 2016
Joe, it seems like you've focused on `super ===
Object.getPrototypeOf(this)` as the overall ideal without considering the
issues with it. I've tried to put together a few counterexamples below. Say
you have a base set up like this:
```
var a = {
prop: null,
method(){
this.prop = 4;
// super.method();
// vs
// Object.getPrototypeOf(this).method.call(this);
return this.prop;
},
};
var b = {
__proto__: a,
method: function(){
this.prop = 5;
// super.method();
// vs
// Object.getPrototypeOf(this).method.call(this);
},
};
var c = {
__proto__: b,
method: function(){
this.prop = 6;
},
};
```
In this example, `super.method()` will work fine, and `a.method() === 6`
because each super call will reassign `this.prop`, where `this === a`.
`Object.getPrototypeOf(this)` has one main core issue here, which is that
we are doing `.call(this);`, meaning that when `a.method()` is called and
subsequently calls `b.method`, `this === a`, not `this === b` inside
`b.method`. This means that when `b` attempts to call _its_ super class, it
has no way of finding `c`, because `this === a` and
`Object.getProtoypeOf(this) === b`, not `c`. This leads to the infinite
recursion case that Bergi mentioned.
The only way for this to work, given your proposal, would be to call
`b.method` with `this === b` instead of `this === a`, e.g. `
Object.getPrototypeOf(this).method.call(Object.getPrototypeOf(this));`, but
that would mean that operations happening inside `b.method`, like the
`this.prop = 5;` would be assigning a property on the wrong object (`b`),
instead of the `a` object, leading to `a.method() === 4`.
ES6 solves this by looking up the parent prototype using the
`[[HomeObject]]` as the root instead of `this`, where `[[HomeObject]]` is
essentially the object that the function was attached to syntactically. The
issue is that a standalone function has no object that it is attached to.
This means that usage of `super.foo` ends up being restricted to only
functions written with method syntax, where they are attached clearly to a
specific object.
On Tue, Jul 19, 2016 at 3:13 AM, Andrea Giammarchi <
andrea.giammarchi at gmail.com> wrote:
> `super === Object.getPrototypeOf(this)` also doesn't work with multiple
> inheritance.
>
> If interested, it has been solved dynamically in this good'ol library:
> https://github.com/WebReflection/es-class#es6-ready
>
> Regards
>
> On Tue, Jul 19, 2016 at 11:03 AM, /#!/JoePea <joe at trusktr.io> wrote:
>
>> Hi Bergi, yes, so the object that `super` references would work like
>> `this`, where the value is determined at runtime instead of in a
>> declaration. Basically, `super === Object.getPrototypeOf(this)` would
>> actually be true in my examples. It may be due to ["extra overhead"](
>> http://disq.us/p/1a56gxj) that `[[HomeObject]]` is only defined during
>> declaration, but that is at the huge expense of making the language less
>> intuitive and also more difficult to work with in some cases (for example,
>> in designing a multiple-inheritance scheme).
>>
>> It would simply be great for super to just work as expected in the
>> examples I gave, which would mean that super would work in tandem and
>> intuitively with the various ways in which we can create
>> objects-extending-objects in JS.
>>
>> Good news is that making the necessary change to `super` in ES8 or later
>> is completely backwards compatible with how it currently works.
>>
>> I wonder what the performance problems are and if they can be solved.
>>
>> */#!/*JoePea
>>
>> On Mon, Jul 18, 2016 at 2:46 PM, Bergi <a.d.bergi at web.de> wrote:
>>
>>> /#!/JoePea wrote:
>>>
>>> Why can't `super` simply be a shortcut
>>>> for "look up the prototype of the object that the method is called on,
>>>> then
>>>> find the `.constructor` property and call it on `this`"? That seems to
>>>> be
>>>> simple.
>>>>
>>>
>>> Simple, yes, and broken in the case of multi-level inheritance:
>>> ```
>>> const x = Object.assign(Object.create({
>>> method() {
>>> console.log("parent");
>>> }
>>> }), {
>>> method() {
>>> console.log("child");
>>> Object.getPrototypeOf(this).method(); // super.method()
>>> }
>>> });
>>> x.method(); // works as expected
>>>
>>> const y = Object.create(x);
>>> y.method(); // infinite loop/stack overflow
>>> ```
>>> A `super` query must not depend on `this` (only), it must statically
>>> resolve the object on which the called method is defined.
>>>
>>> In constructors, using the prototype of the currenctly called
>>> constructor for `super()` works well, but you'd need to use
>>> `Object.setPrototype` as there is currently no declarative way other than
>>> `class`es to define functions with custom prototypes.
>>>
>>> In methods, there would need to be a way to populate the [[HomeObject]]
>>> other than declaring the method as part of a class/object literal.
>>>
>>> Kind regards,
>>> Bergi
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20160719/28d38126/attachment.html>
More information about the es-discuss
mailing list