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

reconciling the disparate function implementation hiding use cases #23

Closed michaelficarra closed 4 years ago

michaelficarra commented 5 years ago

In the previous TC39 meeting, we discovered that there are a number of use cases for "function implementation hiding", and they have some overlapping and some conflicting requirements. Here is my attempt to categorise these requirements so we can decide how we would like to move forward with the proposal more concretely.

Use Cases and Their Requirements

Under each use case for "function implementation hiding", I've listed the individual requirements needed to accomplish the use case's goals.

  1. no information leaks (for security) a. the function does not appear in stack traces b. the function's source text (including parameter list) is not available through F.p.toString
  2. appear as a built-in (for polyfilling) a. the function does appear in stack traces b. the function has no file attribution or position info in stack traces c. the function is rendered as a NativeFunction by F.p.toString
  3. no unintentional API (for libraries) a. the function does appear in stack traces b. the function has no file attribution or position info in stack traces c. the function's source text (including name and parameter list) is not available through F.p.toString d. the function's length property is not necessarily based on its parameter list e. the function's name property is not necessarily based on the syntactic binding
  4. virtualisation a. the function does not appear in stack traces

Features

A grouping of the requirements such that they can be composed to satisfy each use case produces the following "features":

Notes:

Alignment of Use Cases with Features

The minimum features to accomplish each use case:

  1. no information leaks: A ∪ B
  2. appear as a built-in: Ac ∪ B
  3. no unintentional API: Ac ∪ B ∪ C
  4. virtualisation: A

Options

Assuming I've done everything right up to this point, we need to make the following choices:

My preferences:

The reason I've chosen a directive for A and B together instead of keeping them distinct is the desire to have a single opt-in for the security use case, as I described in #8. I am not very opinionated on the polyfilling use case, so I could go either way on the directive for Feature B. Feature C does not seem to pay for itself, since it has good alternatives today.

domenic commented 5 years ago

no information leaks (for security)

We never did document this case very well. In particular, I am curious as to whether this can apply to "public" functions, or only to functions that are called by other "public" functions.

I say this because there are also encapsulation/polyfilling cases where this makes sense, but they have that public/private divide. E.g., using your names,

Array.prototype.somethingCool = function () {
  "polyfill";
  return someHelper(this);
};

function someHelper(arr) {
  "sensitive implementation";
  // ...
}

virtualisation

I don't quite understand how you are using the term here.

My preferences:

I agree with the overall outcomes, although per my above example, I think the names probably need tweaking. (Maybe "internals hidden" vs. "completely hidden" is a theme to think about.)

I think we may be coming up against a complexity budget; folks were already hesitant about one new directive, and two may be stretching it. I'm wondering if there are other tweaks to the "API" we could make to improve that. Or at least we could present some creative alternatives to the committee, if only to show that two directives is the simplest path.

As a handwavey and imprecise example, we could contemplate something like a single module- or class-level directive that has the combined effects of:

michaelficarra commented 4 years ago

The committee went with our recommendation: https://docs.google.com/presentation/d/1lWH97DxTLU3_1EJA-F19uIzagZQx7PZmys7WyNXw3cY/edit#slide=id.g5ded237d17_0_65

For now, we also have "preserve implementation" for resetting the F.p.toString behaviour, though I'm still hoping we can drop this.