domenic / get-originals

A web platform API that allows access to the "original" versions of the global built-in objects' properties and methods
28 stars 1 forks source link

Getting original constructors without names #15

Open littledan opened 6 years ago

littledan commented 6 years ago

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:

  1. Just don't expose them through getOriginalConstructor and expect people to find them another way (this works better for %GeneratorFunction% than %TypedArray%).
  2. Encourage the JS spec to add them as properties of the global object.
  3. Expose them through some other means, for example supporting their spec-internal names, like getOriginalConstructor("%TypedArray%")

I don't have a strong preference between 2 and 3, but 1 would be a little unfortunate.

domenic commented 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:

%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.

jridgewell commented 6 years ago

%PrivateName% (dynamic private fields using weakmap like object) from the decorators proposal isn't (yet, we could change it) exposed on the global.

domenic commented 6 years ago

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.

jridgewell commented 6 years ago

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.

domenic commented 6 years ago

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.

littledan commented 6 years ago

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.

domenic commented 6 years ago

Well, are you concerned about constructors, or methods? Both?

littledan commented 6 years ago

@domenic In this case, more concerned about their methods.

domenic commented 6 years ago

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.

domenic commented 5 years ago

With the current draft this is a definite issue, specifically for %TypedArray% methods.

littledan commented 5 years ago

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.

ljharb commented 5 years ago

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)

littledan commented 5 years ago

@ljharb From JavaScript, you can get at it by calling the next method directly on the object.

ljharb commented 5 years ago

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.