Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prototypes and Privacy #2

Open
jridgewell opened this issue Jan 10, 2019 · 2 comments
Open

Prototypes and Privacy #2

jridgewell opened this issue Jan 10, 2019 · 2 comments

Comments

@jridgewell
Copy link
Owner

Walking up the prototype chain on access to private is something we discussed the last time we looked into "static private" solutions. See the section of that repository for a summary of why we didn't select that option. @ljharb puts it succinctly in #43 (comment) :

it must be possible (and the common, default behavior) that any code whatsoever outside the class declaration, including superclasses or subclasses, can not observe anything about private fields; including their names, their values, their absence, or their mere existence.
@littledan - tc39/proposal-class-fields#183 (comment)

To clarify further, if the word "private" is associated with it, I would expect that statement to apply - thus "private symbols walk the prototype chain" imo is a contradictory sentence.
@ljharb - tc39/proposal-class-fields#183 (comment)

These are both arguing that private symbols are not actually private because they fire observable getPrototypeOf traps (assuming a proxy is somewhere in the prototype chain, or the proxy is the base object).

const obj = { #x: 1 };
const p = new Proxy(obj, {
  getPrototypeOf(target) {
    console.log('observed');
  }
});
const sub = Object.create(p);

// observable prototype lookup
p.#x

// observable prototype lookup
sub.#x

If this is a necessary requirement for privacy, why not just skip the getPrototypeOf trap during prototype lookup? The same as get/set handler tunnel directly to the target, we can define the private symbol lookup algorithm to tunnel directly when traversing the prototype.

@jridgewell
Copy link
Owner Author

After reviewing a bit, this is actually how the current "spec text" works. Since the proxy is transparent when it comes to private symbols, the [[Get]] operation is forwarded directly to the target: Return ? target.[[Get]](P, Receiver) (9.5.8 Step 7).

Although it was my intention to have an observable call to getPrototypeOf, it was never actually spec'd that way in the first place!

@jridgewell
Copy link
Owner Author

jridgewell commented Jan 11, 2019

Further proof:

const target = { test: true }
const proxy = new Proxy(target, {
  get(target, key) {
    // Imitate "transparent" proxy
    return Reflct.get(...arguments);
  },

  getPrototypeOf() {
    throw new Error('observable');
  }
});

console.assert(proxy.test === true);

const sub = Object.create(proxy);
console.assert(sub.test === true);

In fact, no traps are fired (minus the get trap, because I'm imitating):

const target = { test: true }
const proxy = new Proxy(target, new Proxy({}, {
  get(target, key) {
    // Imitate "transparent" proxy
    if (key === 'get') return;

    throw new Error('observable');
  }
}));

console.assert(proxy.test === true);

const sub = Object.create(proxy);
console.assert(sub.test === true);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant