tc39 / proposal-function-implementation-hiding

JavaScript language proposal: function implementation hiding
https://ci.tc39.es/preview/tc39/ecma262/pull/1739
MIT License
98 stars 7 forks source link

Hiding implementation of classes breaks the `is‑callable` package #43

Open ExE-Boss opened 4 years ago

ExE-Boss commented 4 years ago

The is‑callable package uses the /^class\b/u RegExp to determine whether the function is a class, and therefore [[Call]] will immediately throw.

The way to solve this would be to add a NativeClass construct, and return that if [[IsClassConstructor]] is true:

NativeClass :
    `class` PropertyName[~Yield, ~Await]? `(` FormalParameters[~Yield, ~Await] `)` `{` `[` `native` `code` `]` `}`

See also: https://github.com/heycam/webidl/issues/831


/cc @ljharb

ljharb commented 4 years ago

That’s a good point; this proposal should perhaps hide the body and the arguments but not the name or the syntactic outer pieces (consider also: concise object methods, getters/setters, etc)

bathos commented 4 years ago

How does is-callable currently handle platform classes, which already return the generic native code string?

image

Or bound constructors?

image

If NativeClass were added, I would hope it would also mean an update to how bound function objects determine their toString() results and that platform classes could leverage it too. I’m not certain that’s web safe (and conceptually it’s arguable whether it’s “correct”) but it doesn’t make much sense to me to “fix” it for one case and not the others, especially given one of the goals for this proposal is to close gaps related to implementing platform APIs in ES.

(Note that an accurate implementation of an IDL interface in ES requires use of class syntax because one must be able to suppress the externally observable Get(NewTarget, 'prototype') until the correct point, which is only possible when [[ConstructorKind]] is "derived" (even if it’s actually a base class in practice). Implementing them using function syntax is not always equivalent. If using function syntax, Get(NewTarget, 'prototype') would end up occurring twice in a successful case where it should occur only once, or once in certain unsuccessful cases where it should not occur at all. The only work around for this using function syntax is to create platform interface constructors as Proxies that trap construct, but proxies bring their own problems to Function.prototype.toString.)

ljharb commented 4 years ago

On browsers that have the keyword “function”, it’s impossible to detect being a class - but the spec requires the keyword “class” there now as of https://github.com/tc39/Function-prototype-toString-revision and ES2019.

bathos commented 4 years ago

@ljharb I’m not sure I understand. The revision still says:

If func is a Bound Function exotic object or a built-in Function object, then return an implementation-dependent String source code representation of func. The representation must have the syntax of a NativeFunction.

bathos commented 4 years ago

Oh, derp, you were responding to the first part of what I asked rather than the last part I was thinking about, naturally :)