First, I agree with David that security is important, both for security per se and for modularity in general. ES5 improved the language when it fixed the accidental leaks between the world of objects and scope-chain objects, like thrown functions. ES5/strict improved the language when it made functions really encapsulated, poisoned caller and arguments, and repaired the remaining violations of static scoping. ES6 modules and CommonJS/Node modules were born and remain encapsulated. I have not heard anyone suggesting any of these would be improved by introducing pliers for opening them against their will (except in a debugger, which is a different issue). Tons of code have been written in ES3. We still made the world a better place when we plugged its leaks.
I also agree with David that unique symbols are not an encapsulation mechanism, but rather, merely a mechanism to avoid namespace collisions. As for Java's reflective breakage of "private", <http://www.nbcnews.com/technology/technolog/us-warns-java-software-security-concerns-escalate-1B7938755>. However, after the "Private Slots" thread, I spent a sleepless night chewing on getting rid of private symbols. I now think we should. Going back to my earlier On Wed, Jan 16, 2013 at 12:37 PM, Mark S. Miller <erig...@google.com> wrote: > My position on private symbols. > > My position on classes is and has always been that classes are worth > introducing into the language *only* if they give us, or can be used > with, an affordable means for true object encapsulation. Assuming > Allen is right about what actual implementors will do (which I find > plausible) then WeakMaps are not that means. I still have this position on classes. But I no longer buy that pessimistic conclusion about WeakMaps. Consider how WeakMaps would be used by the expansion of classes-with-private. Just 'cause it's on the top of my head, below I use the old representation of one WeakMap per class providing access to a record of all the private state. For the same reason, I'll use the encapsulation of the Purse example without any of the numeric checks. class Purse { constructor(private balance) { getBalance() { return balance; } makePurse() { return Purse(0); } deposit(amount, srcPurse) { private(srcPurse).balance -= amount; balance += amount; } } expansion let Purse = (function() { let amp = WeakMap(); function Purse(balance) { amp.set(this, Object.seal({ get balance() { return balance; }, set balance(newBalance) { balance = newBalance; } })); } Purse.prototype = { getBalance: function() { return balance; }, makePurse: function() { return Purse(0); }, deposit: function(amount, srcPurse) { amp.get(srcPurse).balance -= amount; } } return Purse; })(); Ignore the issues about whether we should use one WeakMap per class and a private record as above, or a WeakMap per private field name declaration. Ignore the use of accessors so that private field names track variables. If we had instead stored the state in the private field and compiled getBalance to use the field, that doesn't affect the important issue. ********************** Notice that the lifetime of amp cannot be shorter than the lifetimes of the Point instances, since the instances retain amp, and these instances are the only objects ever stored as keys in amp. ********************** For this usage common pattern, the lifetime of the keys of amp cannot outlive the lifetime of amp. Thus, no matter what the spec says, normatively or not, about expected storage costs, competitive pressures will drive JS engine implementors to make this efficient. The way to make this efficient is by the technique previously discussed -- hang the private state off of the object, not the weakmap. Use the weakmap only as an unforgeable token for naming and accessing this state. If we get rid of private symbols, we should expect this pattern of usage of WeakMap to have the same cost that private symbols would have had. We can help implementors achieve that by having this expansion call instead "WeakMap(USE_KEY_LIFETIME_HINT)" or whatever it is called. Then implementations would not have to recognize the pattern by other means. Complexity is the enemy of security. We already have four encapsulation mechanisms in ES6 in addition to private symbols: 1) functions encapsulating lexical variables 2) WeakMaps 3) proxies encapsulating handlers and targets 4) modules encapsulating what they don't export. With enough spec and engineering effort, any of these could be grown into a means for providing efficient class/object encapsulation. Of them, I think #2 is most plausible. Even is we find #2 does not work out, we should think about growing one of the other candidates as an alternative to private symbols. Security demands simplicity, and semantic simplicity is more important than implementation simplicity. -- Cheers, --MarkM _______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss