> 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 <isiahmead...@gmail.com>
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/23d67ebec901b3471b84e63f58a96b51a36f3671/lib/jsdom/browser/Window.js#L80
> [4]: https://github.com/jsdom/jsdom/search?q=_globalProxy
> [5]:
> https://github.com/jsdom/jsdom/blob/ad0e551b1b633e07d11f98d7a30287491958def3/lib/jsdom/living/websockets/WebSocket-impl.js#L49
>
> -----
>
> Isiah Meadows
> cont...@isiahmeadows.com
> www.isiahmeadows.com
>
>
> On Tue, Jul 31, 2018 at 1:55 AM, Ranando King <king...@gmail.com> 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 <isiahmead...@gmail.com>
> > 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
> >> cont...@isiahmeadows.com
> >> www.isiahmeadows.com
> >>
> >>
> >> On Mon, Jul 30, 2018 at 9:00 PM, Ranando King <king...@gmail.com>
> 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 <king...@gmail.com>
> 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 <
> isiahmead...@gmail.com>
> >> >> 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
> >> >>> cont...@isiahmeadows.com
> >> >>> www.isiahmeadows.com
> >> >>>
> >> >>>
> >> >>> On Mon, Jul 30, 2018 at 8:04 PM, Ranando King <king...@gmail.com>
> >> >>> 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
> >> >>> > <isiahmead...@gmail.com>
> >> >>> > 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
> >> >>> >> cont...@isiahmeadows.com
> >> >>> >> www.isiahmeadows.com
> >> >>> >>
> >> >>> >>
> >> >>> >> On Mon, Jul 30, 2018 at 6:35 PM, Waldemar Horwat
> >> >>> >> <walde...@google.com>
> >> >>> >> 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
> >> >>> >> es-discuss@mozilla.org
> >> >>> >> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to