Open littledan opened 6 years ago
I think from the perspective of the goals of this API, (1) might be OK. So far, none of the nameless original-constructors have been something that we would use when writing a layered API, or indeed that anyone would use when writing JS code. They seem to mostly exist so that there is a coherent prototype chain, with their construction functionality tossed in as an afterthought.
Concretely, we have:
%ThrowTypeError%
(not really a constructor)%TypedArray%
%TypedArray%
always throws an exception. It's unclear what you could usefully use the original %TypedArray%
for.
Dynamically creating functions from strings is similarly fairly niche, and often discouraged.
I'd welcome counterexamples of where these things could be useful. Especially web platform specs that currently build these constructors, and would be impossible to implement in JS without get-originals exposing them.
%PrivateName%
(dynamic private fields using weakmap like object) from the decorators proposal isn't (yet, we could change it) exposed on the global.
Interesting example. Are there use cases for calling the %PrivateName%
constructor? I'm not familiar with how people are expected to write code against private names, but I would assume that if they were meant to be constructed, it would be exposed as a global.
Are there use cases for calling the %PrivateName% constructor
Yes. You can see a (large, sorry) write up at https://github.com/tc39/proposal-decorators/issues/68#issuecomment-392292586, or the condensed version below.
I would assume that if they were meant to be constructed, it would be exposed as a global
At the moment, they're passed in as an argument to the decorator call, eg:
function bound(descriptor, PrivateName) {
// Create some dynamic private here
const x = new PrivateName('x');
// Do something with it in class methods, etc.
// ...
}
class Example {
@bound x() {}
}
But that makes it a bit odd to use outside of native class decorators, ie for normal objects.
It currently has to be done this way because there's no way to guarantee that PrivateName
hasn't been mucked with (and therefore, your dynamic private isn't private at all) without passing in the %PrivateName%
to the call. Using get-originals was one option to fix that.
Yeah, I think things that are supposed to be used should be exposed globally; half-hearted enforcement of safe meta-programming by having the language pass constructors as arguments to functions seems problematic.
It's not an enforcement mechanism, but more like a design finesse. I don't want people to mistakenly think that PrivateName is anything but a decorator metaprogramming construct, so it's exposed specifically to decorators. Of course it's not hard to get at anyway if you want to.
For people who want to call the original methods on PrivateName.prototype, anf guarantee that there won't be interference with monkey-patching, it would be great if this proposal worked for them.
Well, are you concerned about constructors, or methods? Both?
@domenic In this case, more concerned about their methods.
The methods seem like less of an issue; at least in the current form, callOriginalMethod could still work, regardless of the presence or not of a global constructor.
With the current draft this is a definite issue, specifically for %TypedArray% methods.
Probably more important than %PrivateName%
(which is absent from the current decorators draft) is the WeakRef %FinalizationGroupCleanupIteratorPrototype%
, where you need to call the next
method in order to implement any sort of finalizer. This is present in the Stage 3 draft of WeakRefs, and implemented in V8 behind a flag. I think it's important that built-in module polyfills and WebAssembly be able to register finalizers and use them in a reliable way.
It seems like if a builtin is important/useful enough to warrant direct access via this proposal, that it’s important/useful enough to just be globally reachable? (iow option 2 above)
@ljharb From JavaScript, you can get at it by calling the next
method directly on the object.
sure, that’s true of all prototype methods, and all properties of builtins including static methods, but this proposal seems to be trying to provide a way to get the functions directly without the intermediate object(s). It just doesn’t seem different to me than, say, array slice.
The JavaScript specification includes a few constructors that aren't properties of the global object, such as
%TypedArray%
and%GeneratorFunction%
. What should be done with these? I see a few options:getOriginalConstructor
and expect people to find them another way (this works better for%GeneratorFunction%
than%TypedArray%
).getOriginalConstructor("%TypedArray%")
I don't have a strong preference between 2 and 3, but 1 would be a little unfortunate.