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

Remove PrivateMap #11

Closed
zenparsing opened this issue Nov 27, 2014 · 11 comments
Closed

Remove PrivateMap #11

zenparsing opened this issue Nov 27, 2014 · 11 comments

Comments

@zenparsing
Copy link
Owner

Since "clear" was removed from WeakMap, we no longer have strong motivation for PrivateMap.

@zloirock
Copy link

zloirock commented Dec 3, 2014

I do not understand what a hypothetical PrivateMap (now - simple WeakMap) were better hypothetical PrivateSymbol for private properties. With symbols fewer problems with garbage collection.

@zenparsing
Copy link
Owner Author

So, let's assume that we have a new Symbol subtype that is private. What would the semantics be?

  • They would not be discoverable by Object.getOwnPropertySymbols
  • They would not invoke any traps on proxies.
  • They would not tunnel through proxies to proxy targets.
  • Getting a private-symbol-keyed property would not traverse the prototype chain of the object (perhaps arguable).

When you take these constraints together, you're left with the observable semantics of a WeakMap. (Leaving aside GC considerations of course.)

That's the reasoning behind using WeakMap for private fields.

Furthermore, the WeakMap interface (get/set/has/delete) allows you to pass the access capability across membranes because you can proxy and potentially revoke access to the weak map object. A value type like symbol wouldn't work cross-membrane for private state. One might argue that that isn't important.

The private state thing is still a work in progress. : )

@zloirock
Copy link

zloirock commented Dec 4, 2014

  • They would not invoke any traps on proxies.
  • They would not tunnel through proxies to proxy targets.

I don't think for proxy is a real problem for private state. Rather, the additional possibility. If the symbol key is accessible from the outside, it's not private property.

  • Getting a private-symbol-keyed property would not traverse the prototype chain of the object (perhaps arguable).

Remember old WeakMap#@@referenceGet / Map#@@referenceGet proposal.

Furthermore, the WeakMap interface allows you to pass the access capability across membranes

Yes, indeed an advantage. But private symbols could implement such a proxy / getters / setters as simple properties (though more difficult).

It would be nice to implement both types of private properties for different cases and the PrivateSymbol (Name in old strawman) seem to me more attractive.

@domenic
Copy link

domenic commented Dec 4, 2014

I asked @erights to explain to me why private symbols don't interact well with membranes at the last TC39 meeting, and I even took notes!! Here they are cleaned up a bit:


Conceptually, you have two operations:

set(o, k, v)
v = get(o, k)

In the private symbol scenario, k is a private symbol, set = (o, k, v) => o[k] = v, and get = (o, k) => o[k].

In the weak map scenario, k is a weak map, set = (o, k, v) => k.set(o, v), and get = (o, k) => k.get(o).

Each of the three objects o, k, and v might be on either side of the membrane (dry or wet). Given that there are three objects with two possibilities each, that gives 23 = 8 scenarios.

Any solution must satisfy these two correctness constraints:

  1. Across all eight of the scenarios, a set on one side of the membrane followed by a get on the other side of the membrane, yields the value corresponding to the one originally set on the other side.

    (TODO: write up a few illustrative examples using o, k, v and o', k', v'.)

  2. When you try to look up a property on a proxy that does not have (and is not authorized to see) the property, you do not leak to the proxy the ability to see the property.

Given these two constraints, we can see why private symbols can't work:

  • If a private symbol passes literally through proxies, then the ability to see the corresponding property leaks, violating constraint 2.
  • However if private symbols don't pass literally through the proxies, then we violate constraint 1.

A long time ago on es-discuss, there was talk of various complicated mechanisms that let the private symbol sometimes pass through the proxies and sometimes not, but according to @erights in general each mechanism they discovered failed at least one of the eight cases, and attempts to plug those holes just ended up adding much more complexity. In the end the complexity turned out to be needless if you just invert the relationship and use the weak map mechanism!

Here's another way of looking at the situation that might be more intuitive:

Let's say v, o, and k are all proxies. When you do v = get(o, k), who gets access to what? The private symbol answer is that o gets access to k. The weak map answer is that k gets access to o. The former violates the constraints as above; the latter does not.

See also: bottom section of http://wiki.ecmascript.org/doku.php?id=strawman:relationships


That said, I think implementers are still pushing back against WeakMap itself being the correct class, as recent es-discussions elaborate. But the semantics seem correct.

@erights
Copy link

erights commented Dec 4, 2014

Thanks!!!!

On Thu, Dec 4, 2014 at 3:32 PM, Domenic Denicola notifications@github.com
wrote:

I asked @erights https://github.com/erights to explain to me why
private symbols don't interact well with membranes at the last TC39

meeting, and I even took notes!! Here they are cleaned up a bit:

Conceptually, you have two operations:

set(o, k, v)
v = get(o, k)

In the private symbol scenario, k is a private symbol, set = (o, k, v) =>
o[k] = v, and get = (o, k) => o[k].

In the weak map scenario, k is a weak map, set = (o, k, v) => k[o] = v,
and get = (o, k) => k[o].

Each of the three objects o, k, and v might be on either side of the
membrane (dry or wet). Given that there are three objects with two
possibilities each, that gives 23 = 8 scenarios.

Any solution must satisfy these two correctness constraints:

Across all eight of the scenarios, a set on one side of the membrane
followed by a get on the other side of the membrane, yields the value
corresponding to the one originally set on the other side
.

(TODO: write up a few illustrative examples using o, k, v and o', k',
v'.)
2.

When you try to look up a property on a proxy that does not have (and
is not authorized to see) the property, you do not leak to the proxy the
ability to see the property.

Given these two constraints, we can see why private symbols can't work:

  • If a private symbol passes literally through proxies, then the
    ability to see the corresponding property leaks, violating constraint 2.
  • However if private symbols don't pass literally through the proxies,
    then we violate constraint 1.

A long time ago on es-discuss, there was talk of various complicated
mechanisms that let the private symbol sometimes pass through the proxies
and sometimes not, but according to @erights https://github.com/erights
in general each mechanism they discovered failed at least one of the eight
cases, and attempts to plug those holes just ended up adding much more
complexity. In the end the complexity turned out to be needless if you just
invert the relationship and use the weak map mechanism!

Here's another way of looking at the situation that might be more
intuitive:

Let's say v, o, and k are all proxies. When you do v = get(o, k), who
gets access to what? The private symbol answer is that o gets access to k.
The weak map answer is that k gets access to o. The former violates the
constraints as above; the latter does not.

See also: bottom section of

http://wiki.ecmascript.org/doku.php?id=strawman:relationships

That said, I think implementers are still pushing back against WeakMap
itself being the correct class, as recent es-discussions elaborate. But the
semantics seem correct.


Reply to this email directly or view it on GitHub
#11 (comment)
.

Text by me above is hereby placed in the public domain

Cheers,
--MarkM

@zloirock
Copy link

zloirock commented Dec 5, 2014

Interesting. Thanks.

@yuchi
Copy link

yuchi commented Dec 11, 2014

@erights, enlightening.

@uMaxmaxmaximus
Copy link

uMaxmaxmaximus commented Jul 22, 2016

My solution: Yes, these properties can be obtained through Object.getOwnPropertySymbols.

BUUUT!! Private property is not protected against hackers !! It's only an abstraction, which allows to avoid conflicts NAMES !!

In addition, we may well make 2 functions:

  1. Object.getOwnPropertySymbols() return symbols that have been set in current file
  2. Object.getOwnPropertySymbolsAll() return symbols that have been set in ALL files

@HyeonuPark
Copy link

No idea about the meaning of "dry/wet membrane". Can someone explain it please?
And also, should Proxy<Symbol> treated as a Symbol? I thought it's just a plain Proxy object that targets Symbol.

@spion
Copy link

spion commented Apr 6, 2017

If I understand correctly, the simplified explanation is as follows:

Even if we added {hidden: true} to Object.defineProperty which ensures that there is no way to get the property symbol (through Object.getOwnPropertySymbols(o)), there is still the Proxy problem:

Basically, when you do this[privateSymbol] or otherObject[privateSymbol], you are announcing that privateSymbol to the object (this / otherObject)

Both of these can be intercepted by a proxy that wraps the original object and traps all property lookups to that object. The first time a method is invoked that tries to access the privateSymbol property, this symbol will be passed to the get proxy handler. After that, the code that created the proxy has access to the symbol and therefore direct access to the private properties of the original object.

@erights
Copy link

erights commented Apr 6, 2017

Hi @spion yes, that is an accurate summary of the most important issue. By itself one could imagine "fixing" this problem with a more complex API, which an earlier proposal actually tried to do. But that got really complicated and left other fundamental problems unsolved.

Rather that re-explain here what those remaining problems are, once wiki.ecmascript.org is back online (attn @dherman ) I can point you at some useful explanations.

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

8 participants