Should a sealed/frozen object be privately extensible? I don't actually know, but interesting point.
On Tuesday, July 31, 2018, Ranando King <[email protected]> wrote: > > Consider what people often use public symbols for now. > > I know that I use them as fixed-value unique keys (module globals) for > properties on objects that I export and don't want others to be aware of or > able to touch. > > > For example, consider this library [1]. In this case, they use a public > symbol for their stuff in this file [2]. > > And as I said before, if someone passes a non-extensible object to this > library, it breaks. Since any library can request any object be sealed or > frozen, the implementation of this library is too fragile. > > > Because here, it's not a cache, but it's literally extra associated > data in the object. And also, in that case, you *want* the engine to see > it as a property, since it can employ relevant IC caching for it. > > Here's a parallel for you. Right now, Google has a database with > information about me on it. I don't have access to that information (module > privacy) and that information isn't stored anywhere on me or my devices > (module locality). This is a proper conceptual model. The information > Google is keeping about me is information they generated. Why should I have > to pay to store their information? Thankfully I don't. However, this is > precisely what you're claiming to be a good use case. You want module > privacy without module locality. If I were to play at a Kevin Gibbons-like > response, I'd say you've identified the common pattern, but that pattern > itself is a bad use case, and the use of private symbols as you have > defined them doesn't do anything to correct the technical issue. Since you > cannot stick new properties onto a non-extensible object, even private > symbols won't solve the problem with your use case. > > > No, I'm not. I'm drawing a distinction between a pure many-to-one > > association > (weak maps) and a "has a" relationship (private symbol properties). > > First, for any given property bag, the keys will need to be unique, but > that doesn't force uniqueness onto the values. As such, even properties on > an object provided by your "private Symbol" would still be many-1. When a > 3rd party library wants to keep information associated with an arbitrary > object, there are only 3 choices: > * try to store that information on the object > * this is what you're advocating, but it's not a good pattern. It's too > fragile, being subject to break if the incoming object is not extensible. > * store the information as being associated to the object (WeakMap) > * this is the pattern that works in all cases (but the syntax is > cumbersome and the implementation somewhat slow) > * return a wrapper containing the original object and the new information > (Proxy or custom wrapper) > * this is another possibility, but requires that any users accept and > use the new Proxy or wrapper object in lieu of the original. > > > Another scenario is for JSDOM's `Window` implementation, where they have > a few underscore-private variables like this [3]. That particular variable > is used in several disparate parts throughout the code base [4], but is > still conceptually a property. This is a case where a private symbol > property is appropriate. > > It's not just "conceptually" a property. It's logically a property. Why? > Because all the objects that it exists on were constructed somewhere within > the JSDOM library. That's me putting _my_ keys in _my_ pocket. There's > absolutely nothing wrong with that. > > > Conversely in this JSDOM file [5], it's just associating data with an > > arbitrary > object it happens to have, and so using the weak map makes perfect sense. > > Conceptually speaking, this is the same scenario as SymbolTree. In both > cases, the library is generating information associated with an object it > doesn't own and didn't create. > > > BTW, you could make a similar argument against superclass private fields > - it's like hiding valuable info in your wallet before you receive it for > the first time, but even after dismantling it, you can't find any > evidence of that valuable info. > > That dog don't hunt. The difference here is that in your use cases, > library A is "sneakily" storing information on object B. In the case of > superclass private fields, subclass B has "volunteered" to take on the > information and functionality of class A. You've essentially compared > apples and asteroids just because they both begin with "a". > > On Tue, Jul 31, 2018 at 2:15 AM Isiah Meadows <[email protected]> > wrote: > >> > Isn't this precisely what WeakMaps are for? If the data is >> > "module-internal", then the module needs to be the owner of the data >> store. >> > If the data is about "arbitrary objects" (object from outside the >> module?) >> > then those objects are the keys to the data store. If any object is >> thrown >> > away, the associated data is no longer needed. If this doesn't fit the >> > functionality of a WeakMap, I don't know what will. >> >> Consider what people often use public symbols for now. For example, >> consider this library [1]. In this case, they use a public symbol for >> their stuff in this file [2]. >> >> But here's the thing: that doesn't really need discoverable, and is a >> pure implementation detail. Wouldn't it make more sense for them to >> just use a private symbol instead? Because here, it's not a cache, but >> it's literally extra associated data in the object. And also, in that >> case, you *want* the engine to see it as a property, since it can >> employ relevant IC caching for it. >> >> > Isn't that precisely what your question calls for? You're caching >> > module-internal data about external objects. >> >> No, I'm not. I'm drawing a distinction between a pure many-to-one >> association (weak maps) and a "has a" relationship (private symbol >> properties). You *could* implement one in terms of the other, but >> these two types of relationships are *completely* different at a >> conceptual level and how you model them. >> >> For js-symbol-tree, it's not simply associating a node to a value, but >> setting up the object so it *has* the data required for a doubly >> linked list tree node. Because this symbol is repeatedly accessed, >> it's not caching so much as it's adding data the object needs for it >> to do what it needs to do. >> >> Another scenario is for JSDOM's `Window` implementation, where they >> have a few underscore-private variables like this [3]. That particular >> variable is used in several disparate parts throughout the code base >> [4], but is still conceptually a property. This is a case where a >> private symbol property is appropriate. >> >> Conversely in this JSDOM file [5], it's just associating data with an >> arbitrary object it happens to have, and so using the weak map makes >> perfect sense. >> >> > Likewise, I'm specifically against the abuse of objects to store state >> > unrelated to the factory that created it. To me, that's as if I came to >> > visit you and somehow you managed to hide some valuable info in my >> wallet >> > without me noticing, and even if I completely dismantle my wallet, I >> > wouldn't be able to find it. But somehow you can easily retrieve it the >> next >> > time I come around. That's just conceptually weird. >> >> All of the examples here I've presented are for scenarios where the >> state *is* related to the factory that created the objects. It's not >> *directly* related (and thus encapsulation is warranted), but it's >> still *related*, enough so that you usually see the state initialized >> within the creator's constructor call. It's about as related as the >> superclass is to a subclass of it. >> >> BTW, you could make a similar argument against superclass private >> fields - it's like hiding valuable info in your wallet before you >> receive it for the first time, but even after dismantling it, you >> can't find any evidence of that valuable info. >> >> [1]: https://github.com/jsdom/js-symbol-tree >> [2]: https://github.com/jsdom/js-symbol-tree/blob/master/lib/ >> SymbolTree.js#L28 >> [3]: https://github.com/jsdom/jsdom/blob/23d67ebec901b3471b84e63f58a96b >> 51a36f3671/lib/jsdom/browser/Window.js#L80 >> [4]: https://github.com/jsdom/jsdom/search?q=_globalProxy >> [5]: https://github.com/jsdom/jsdom/blob/ad0e551b1b633e07d11f98d7a30287 >> 491958def3/lib/jsdom/living/websockets/WebSocket-impl.js#L49 >> >> ----- >> >> Isiah Meadows >> [email protected] >> www.isiahmeadows.com >> >> >> On Tue, Jul 31, 2018 at 1:55 AM, Ranando King <[email protected]> wrote: >> >> One last thing: how would you hope to deal with module-internal data >> >> stored on arbitrary objects, using any means other than private >> symbols or >> >> something similar? >> > >> > Isn't this precisely what WeakMaps are for? If the data is >> > "module-internal", then the module needs to be the owner of the data >> store. >> > If the data is about "arbitrary objects" (object from outside the >> module?) >> > then those objects are the keys to the data store. If any object is >> thrown >> > away, the associated data is no longer needed. If this doesn't fit the >> > functionality of a WeakMap, I don't know what will. >> > >> >> Weak maps make sense when the weak map is the dictionary conceptually >> >> (think: caching). >> > >> > Isn't that precisely what your question calls for? You're caching >> > module-internal data about external objects. >> > >> >> Keep in mind, I'm specifically *against* the abuse of weak maps for >> >> private state that's conceptually (in an abstract sense, not runtime) >> part >> >> of an object. >> > >> > Likewise, I'm specifically against the abuse of objects to store state >> > unrelated to the factory that created it. To me, that's as if I came to >> > visit you and somehow you managed to hide some valuable info in my >> wallet >> > without me noticing, and even if I completely dismantle my wallet, I >> > wouldn't be able to find it. But somehow you can easily retrieve it the >> next >> > time I come around. That's just conceptually weird. >> > >> > On Mon, Jul 30, 2018 at 9:42 PM Isiah Meadows <[email protected]> >> > wrote: >> >> >> >> The reason private symbols are appropriate for Node's use case is >> >> because it's conceptually a mixin, not a simple key/value map with >> >> various utility functions (and weak map lookup is slower than property >> >> access). JSDOM uses a similar utility [1] as a sort of mixin. >> >> >> >> Keep in mind, I'm specifically *against* the abuse of weak maps for >> >> private state that's conceptually (in an abstract sense, not runtime) >> >> part of an object. Weak maps make sense when the weak map is the >> >> dictionary conceptually (think: caching). But if conceptually, the >> >> object is the dictionary, putting it in a weak map is giving the >> >> engine the wrong info - properties have inline caches and heavy >> >> optimization, but you can't do the same for weak maps in the other >> >> direction without literally implementing them as properties. (I would >> >> *love* to be proven wrong here, BTW.) >> >> >> >> Let me draw a quick comparison: When do you use a map/set with string >> >> keys, and when do you use an object instead? >> >> >> >> - Both are functionally equivalent, but engines use *very* different >> >> algorithms for each one. >> >> - I can almost guarantee you don't use maps when object properties >> work. >> >> >> >> One last thing: how would you hope to deal with module-internal data >> >> stored on arbitrary objects, using any means other than private >> >> symbols or something similar? To clarify, I'm talking of opaque object >> >> structs [2], not simply classes. (BTW, that one is easier to manage as >> >> a struct rather than a class, because of how many "methods" there are >> >> operating on the state.) >> >> >> >> [1]: https://github.com/jsdom/js-symbol-tree >> >> [2]: https://github.com/isiahmeadows/enigma/blob/master/src/parser.ts >> >> >> >> ----- >> >> >> >> Isiah Meadows >> >> [email protected] >> >> www.isiahmeadows.com >> >> >> >> >> >> On Mon, Jul 30, 2018 at 9:00 PM, Ranando King <[email protected]> >> wrote: >> >> > I meant to say if the object passed to the 3rd party function..... >> >> > >> >> > >> >> > On Mon, Jul 30, 2018 at 7:59 PM Ranando King <[email protected]> >> wrote: >> >> >> >> >> >> Just that use case alone is problematic. If the 3rd party function >> is >> >> >> not >> >> >> extensible, then the new private data should not be allowed. If the >> >> >> library >> >> >> cannot function without storing that data, then the function will >> have >> >> >> no >> >> >> choice but to fall back to WeakMaps which don't care if the key is >> not >> >> >> extensible. So why not just stick with WeakMaps for that case? And >> if >> >> >> that's >> >> >> the case, then there would be little need for so open a means of >> >> >> defining >> >> >> private field names. The proposal I'm offering offers the room to >> >> >> extend it >> >> >> in the future to support everything else you might look for from >> your >> >> >> private symbols idea.... unless you think I missed something. >> >> >> >> >> >> On Mon, Jul 30, 2018 at 7:26 PM Isiah Meadows < >> [email protected]> >> >> >> wrote: >> >> >>> >> >> >>> That is one supported use case, yes. But that isn't the only use >> case >> >> >>> this supports. It can still extend to traditional private class >> data, >> >> >>> too. >> >> >>> >> >> >>> ----- >> >> >>> >> >> >>> Isiah Meadows >> >> >>> [email protected] >> >> >>> www.isiahmeadows.com >> >> >>> >> >> >>> >> >> >>> On Mon, Jul 30, 2018 at 8:04 PM, Ranando King <[email protected]> >> >> >>> wrote: >> >> >>> > So you're wanting the ability for a 3rd-party function to be >> able to >> >> >>> > store >> >> >>> > data private to that library on an object it didn't create, and >> that >> >> >>> > only >> >> >>> > that library can access? >> >> >>> > >> >> >>> > On Mon, Jul 30, 2018 at 6:36 PM Isiah Meadows >> >> >>> > <[email protected]> >> >> >>> > wrote: >> >> >>> >> >> >> >>> >> First, my private symbols are properly *private*. The only >> >> >>> >> "unexpected" thing that could happen is making an object larger >> >> >>> >> memory-wise, which engines already have to be equipped to handle >> >> >>> >> now >> >> >>> >> (libraries aren't always well-behaved, and like to occasionally >> add >> >> >>> >> expando properties to builtins and DOM elements). About the only >> >> >>> >> thing >> >> >>> >> most people would care about is in the debugger. >> >> >>> >> >> >> >>> >> Second, I had things like this in mind with supporting expando >> >> >>> >> properties: >> >> >>> >> >> >> >>> >> >> >> >>> >> https://github.com/nodejs/node/blob/ >> ae4fde8bc883686def5badfb324236320669e8f4/lib/internal/linkedlist.js >> >> >>> >> >> >> >>> >> In that case, the Node.js people made it a pseudo-mixin rather >> than >> >> >>> >> an >> >> >>> >> actual type for performance reasons - there's fewer object >> >> >>> >> allocations >> >> >>> >> and they needed that. >> >> >>> >> >> >> >>> >> So I've considered the expando problem, and I disagree about it >> >> >>> >> being >> >> >>> >> a problem at all. >> >> >>> >> >> >> >>> >> ----- >> >> >>> >> >> >> >>> >> Isiah Meadows >> >> >>> >> [email protected] >> >> >>> >> www.isiahmeadows.com >> >> >>> >> >> >> >>> >> >> >> >>> >> On Mon, Jul 30, 2018 at 6:35 PM, Waldemar Horwat >> >> >>> >> <[email protected]> >> >> >>> >> wrote: >> >> >>> >> > On 07/29/2018 04:37 PM, Isiah Meadows wrote: >> >> >>> >> >> >> >> >>> >> >> BTW, I came up with an alternate proposal for privacy >> >> >>> >> >> altogether: >> >> >>> >> >> https://github.com/tc39/proposal-class-fields/issues/115 >> >> >>> >> >> >> >> >>> >> >> TL;DR: private symbols that proxies can't see and that can't >> be >> >> >>> >> >> enumerated. >> >> >>> >> > >> >> >>> >> > >> >> >>> >> > Aside from syntax, the main semantic difference I see between >> >> >>> >> > this >> >> >>> >> > alternative and the main one is that this alternative defines >> >> >>> >> > private >> >> >>> >> > fields >> >> >>> >> > as expandos, creating opportunities for mischief by attaching >> >> >>> >> > them >> >> >>> >> > to >> >> >>> >> > unexpected objects. Aside from privacy, one of the things the >> >> >>> >> > private >> >> >>> >> > fields proposal gives you is consistency among multiple >> private >> >> >>> >> > fields >> >> >>> >> > on >> >> >>> >> > the same object. In the rare cases where you don't want that, >> >> >>> >> > you >> >> >>> >> > could >> >> >>> >> > use >> >> >>> >> > weak maps. >> >> >>> >> > >> >> >>> >> > Waldemar >> >> >>> >> _______________________________________________ >> >> >>> >> es-discuss mailing list >> >> >>> >> [email protected] >> >> >>> >> https://mail.mozilla.org/listinfo/es-discuss >> >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

