ljharb / es-abstract

ECMAScript spec abstract operations.
MIT License
114 stars 30 forks source link

Classes are callable #139

Closed zloirock closed 3 years ago

zloirock commented 3 years ago
require('es-abstract/2020/iscallable')(class{}) // => false

image image

zloirock commented 3 years ago

It seems a duplicate of #48 and #93, but any actions are missed for some years.

ljharb commented 3 years ago

It is indeed a duplicate of both; no action will likely be taken for some decades, given that the real problem is the specification - class constructors are not actually callable, they just implement this with a [[Call]] slot that throws a type error. There’s no use case whatsoever for IsCallable returning true here just to throw later (since IsCallable checks basically always guard a Call).

Filing a redundant issue won’t get things moving any more than a comment on the actual issue would, fwiw.

zloirock commented 3 years ago

In this case, positioning of es-abstract as a proper set of ECMAScrpt spec abstract operations makes no sense.

ljharb commented 3 years ago

This isn't a productive argument. es-abstract is ES AOs for use in polyfills. If you can find a bug in a polyfill caused by IsCallable returning false for a class constructor, I'd be happy to fix it, but if it's just changing when an error is called (because class constructors aren't callable) then it's perfectly reasonable to make choices to deviate from the spec for practicality.

zloirock commented 3 years ago

This isn't a productive argument.

This is a productive argument. Even typeof something === 'function' is a proper IsCallable check for modern engines. Sure, some old engines have some minor issues (like FF2 callable regexes - but they are callable). But es-abstract/2020/iscallable returns false for classes. By the spec, classes should be callable and in too many cases in the spec [[Construct]] checked only when [[Call]] existent - so classes will not pass this check when they should., so this helper should never be used as an equal of abstract ES IsCallable operation in polyfills.

zloirock commented 3 years ago

The behavior of classes:

function C() {
  if (!new.target) throw TypeError();
}

But it does not remove this [[Call]] from this function.

ljharb commented 3 years ago

Yes, I'm aware - and your C function there is effectively not callable, so it's most useful if an "is callable" check returns false for it. In that case, of course, it's not practically possible to do so, but that doesn't mean there's no value in doing so for classes.

zloirock commented 3 years ago

IsCallable should check is this function callable by the spec, not effectively - otherwise, it's not an ECMAScript abstract operation.

ljharb commented 3 years ago

Thanks, your opinion is noted, and the issue is already tracked in #48.