Security Demands Simplicity (was: Private Slots)
allen at wirfs-brock.com
Sun Jan 20 16:29:23 PST 2013
On Jan 20, 2013, at 2:27 PM, Brendan Eich wrote:
> Skipping contentious stuff (some of which, e.g. "classes as sugar", I agree with -- and so does TC39) to get to this paragraph:
> Allen Wirfs-Brock wrote:
>> The [[Get]] and [[Set]] (and probably some others) internal methods of a proxy never call the corresponding trap when the property key is a private Symbol. Instead, they trace the [[Target]] chain of the proxy until a non-proxy object is reached (call this the "ultimate target"). It then invokes the ultimate target's [[Gett]]/[[Set]] using that same private Symbol key. The result of that operation is then returned as the value of the original [[Get]]/[[Set]].
>> The "private" state access is applied to the correct object and there is no exposure of the private symbol!
> If I want to proxy for a date instance I might rather have @@DateValue available and passed as a name to get and set traps, so I can keep my own time number, and not have to delegate to a Date prototype that has the right milliseconds since the Epoch.
For the above I'm thinking of situations where an external party (a membrane?) is wrapping an object that wasn't specifically designed to be proxied. That presumably is the use case that people are primarily concerned about in the recent discussions. As far as I can tell, without special accommodations for all the built-ins' internal state they just don't work if proxied in that manner because the "wrong" this value is passed to all of the methods. Same as for previous proposal for censoring private symbols.
I actually don't see why you would ever need to use a Proxy to implement a ES compatible data abstraction. There is nothing about that abstractions (unlike Array, for example) that requires changing the MOP level behavior manifested by its instances.
Mostly what we are dealing with, WRT Date, is balancing legacy compatibility issues with subclassability issues. The legacy spec for all the Date prototype methods says they throw if they are applied to a this value that does not have the internal state of a Date instance. Among other things, this allows implementations to use custom c structs for Date instances and implement access to the timeValue as a impl level brand check followed by a direct slot access. The ES6 specification of these methods is intentionally vague (the timeValue is in the [[DaveValue]] "internal data property" (which could be implemented using a private Symbol keyed property) rather than explicitly specified as a private Symbol keyed property. This (along with the @@create method) allows subclass to have the same private state layout as the superclass and allows it to be recognized by the methods.
Because of this design, the Date prototype methods are only usable on objects that are allocated using Date.@@create (subclasses achieve this via class-side inheritance). It would arguably be a better OO design to have all those methods access the timeValue via a specified @@DateValue method call. Then they could be install on any object that supplies (possibly via inheritance) such a method. But that design seems to make it harder to use an optimization object struct and possibly to perfectly duplicate the legacy failure behavior.
> Perhaps you're in favor of that in addition? But if so, how would one proxy such that the @@DateValue symbol was the name parameter to get and set traps?
I'm not sure if you are getting at something other than what I've described above. If a @@DateValue private symbol is actually used as the implementation of [[DateValue]] then actuality that would happen.
Were you thinking about something different?
More information about the es-discuss