Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent constructor return checks for base and derived classes #2291

Open
nicolo-ribaudo opened this issue Jan 31, 2021 · 3 comments
Open

Comments

@nicolo-ribaudo
Copy link
Member

Description:

Consider these two classes:

let thisObject;

class A {
  constructor() {
    thisObject = this;
    return x;
  }
}

class B extends class {} {
  constructor() {
    super();
    thisObject = this;
    return x;
  }
} 

when instantiated, they have different behaviors depending on the value of x:

value of x result of new A() result of new B()
a non-null object or a function x x
undefined thisObject thisObject
any other primitive thisObject TypeError

I don't see any spec-reason to have different behaviors in the "base" and "derived" classes.
I think both classes should throw, or (if throwing is web-incompatible) both should return thisObject.

eshost Output:

All the engines (except for Hermes, which always throws a SyntaxError) conform to the specification.

Both Babel and TypeScript return thisObject instead of throwing a TypeError (I discovered this inconsistency while improving Babel's spec compliance).

context/history

The step that throws the TypeError (12.c of [[Construct]]) has been in the spec since the creation of spec.html in this repository.

I couldn't find anything on ESDiscuss except for https://esdiscuss.org/topic/should-the-default-constructor-return-the-return-value-of-super#content-24: it looks in an es2015 draft classes didn't return the result of super() by default.

There is some discussion related to how super() initializes the default this at https://github.com/tc39/notes/blob/827c5f98554b6e04d81c2c265f78f6f7ddf8415a/meetings/2014-09/sept-24.md, and there was a mention by BE that when instantiating an es5 function, if it returns a primitive you always get back the this object.

@raulsebastianmihaila
Copy link

We were close to fixing this a few years ago:
https://esdiscuss.org/topic/primitive-values-from-class-constructors
#469

@nicolo-ribaudo
Copy link
Member Author

nicolo-ribaudo commented Jan 31, 2021

Thanks for the links!

I see that #469 was closed because v8's metrics show that ~1.5% of the web relies on returning primitives from the constructor (#469 (comment)). However, I wonder if that data only includes new class { constructor() { return 1 } } or also new function() { return 1 }: I tried manually checking ~20 of the "Sample URLs" at https://www.chromestatus.com/metrics/feature/timeline/popularity/2054 relying on this behavior, and none of them was using the class keyword 🤔

@ljharb
Copy link
Member

ljharb commented Jan 31, 2021

@gsathya can you confirm whether the above metric differentiated between class and function?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants