!Re: proposal: Object Members

Isiah Meadows isiahmeadows at gmail.com
Mon Jul 30 06:25:14 UTC 2018


Um, no. The use case is *extremely* limited, and that ruins a few
optimizations you could otherwise make with private symbols (like
caching proxy forwarding without having to bail out).

Besides, whether a symbol is private requires exactly one bit to
store, so there's no real overhead with storing it on the object.
Heck, if you want to optimize it better, you might choose to store
that same bit on both the symbol and the object descriptor itself, and
I'd expect engines to do just that - it saves a pointer dereference.
-----

Isiah Meadows
me at isiahmeadows.com
www.isiahmeadows.com


On Mon, Jul 30, 2018 at 1:25 AM, Michael Theriot
<michael.lee.theriot at gmail.com> wrote:
> Also throwing this out there, symbols would now carry additional
> information: private or normal. Would it be better to configure this on
> objects instead?
>
> E.g. `Object.setPropertySymbolVisibility(object, symbol, true / false)`
>
> (and then ideally sugar for this)
>
> That way a symbol's visibility on an object is information held on the
> object rather than the primitive. A little more work involved, but lines up
> with Object.defineProperty and symbols remain purely unique identifiers.
>
> On Monday, July 30, 2018, Isiah Meadows <isiahmeadows at gmail.com> wrote:
>>
>> I'm aware it's possible to misuse, but if concerns of misuse were a
>> serious issue, we wouldn't have iterators, for example [1] [2]. But
>> IMHO freeing weak maps from a role they weren't designed for
>> substantially outweighs the risks of abusing them further (and the
>> abuses are incredibly frequent).
>>
>> [1]:
>> https://esdiscuss.org/topic/iterators-generators-finally-and-scarce-resources-was-april-10-2014-meeting-notes
>> [2]: https://esdiscuss.org/topic/resource-management
>>
>> -----
>>
>> Isiah Meadows
>> me at isiahmeadows.com
>> www.isiahmeadows.com
>>
>>
>> On Sun, Jul 29, 2018 at 10:55 PM, Michael Theriot
>> <michael.lee.theriot at gmail.com> wrote:
>> > Right, I wouldn't, but I'm concerned others would misuse it. I don't
>> > think
>> > it's a blocker though, and actually frees weakmaps from trying to fill
>> > this
>> > role.
>> >
>> >
>> > On Sunday, July 29, 2018, Isiah Meadows <isiahmeadows at gmail.com> wrote:
>> >>
>> >> It will, but weak maps will still remain useful for cases when you're
>> >> semantically dealing with a key/value map. In theory, you could
>> >> implement a weak map on top of this [1], but in practice, it doesn't
>> >> always make sense to do it. A good example of this is if you are
>> >> "tagging" an object with data. If this data isn't really part of the
>> >> object itself, you shouldn't be using a private symbol for it. Another
>> >> good example is if you're doing simple caching and you need to clear
>> >> the weak map by replacing it. Using private symbols for this doesn't
>> >> really fit with the domain here, so you're more likely just to confuse
>> >> future readers (including yourself) if you do this.
>> >>
>> >> [1]:
>> >> https://gist.github.com/isiahmeadows/a8494868c4b193dfbf7139589f472ad8
>> >> -----
>> >>
>> >> Isiah Meadows
>> >> me at isiahmeadows.com
>> >> www.isiahmeadows.com
>> >>
>> >>
>> >> On Sun, Jul 29, 2018 at 10:05 PM, Michael Theriot
>> >> <michael.lee.theriot at gmail.com> wrote:
>> >> > Private symbols sounds like an easy win. They would be painfully
>> >> > simple,
>> >> > real properties, not just variables with property imitation syntax
>> >> > that
>> >> > undoubtedly confuses people. With the added benefit that children can
>> >> > truly
>> >> > override the base class, freedom to define private members shared
>> >> > across
>> >> > otherwise unrelated objects, and even injection. My only concern is
>> >> > that
>> >> > it
>> >> > could cross into WeakMap use cases.
>> >> >
>> >> >
>> >> > On Sunday, July 29, 2018, Isiah Meadows <isiahmeadows at gmail.com>
>> >> > 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.
>> >> >> -----
>> >> >>
>> >> >> Isiah Meadows
>> >> >> me at isiahmeadows.com
>> >> >> www.isiahmeadows.com
>> >> >>
>> >> >>
>> >> >> On Sun, Jul 29, 2018 at 12:23 AM, Darien Valentine
>> >> >> <valentinium at gmail.com> wrote:
>> >> >> >> What you're essentially asking for is a violatable private field,
>> >> >> >> or
>> >> >> >> as
>> >> >> >> has been described by others, a "soft private".
>> >> >> >
>> >> >> > We might have different definitions here, but I would describe
>> >> >> > what
>> >> >> > I’m
>> >> >> > talking about as hard private. Soft private, at least as it
>> >> >> > appears
>> >> >> > to
>> >> >> > have
>> >> >> > been defined in [prior
>> >> >> >
>> >> >> >
>> >> >> > discussions](https://github.com/tc39/proposal-private-fields/issues/33),
>> >> >> > described an avenue where symbol keyed properties were given a new
>> >> >> > syntactic
>> >> >> > form — but they were still just regular symbol keys, and therefore
>> >> >> > could
>> >> >> > be
>> >> >> > introspected by outside agents who had not been given express
>> >> >> > privilege
>> >> >> > to
>> >> >> > do so:
>> >> >> >
>> >> >> >> [...] the core would be that "private state" is simply (public)
>> >> >> >> symbol-named properties, with syntactic sugar for those symbols,
>> >> >> >> and
>> >> >> >> possibly some kind of introspection over them [...]
>> >> >> >
>> >> >> > The thread goes on to contrast the soft model with an earlier
>> >> >> > version
>> >> >> > of
>> >> >> > the
>> >> >> > private fields proposal seen today. The hard private example uses
>> >> >> > the
>> >> >> > class
>> >> >> > declaration as a pseudo-scope, but contrasting these two options
>> >> >> > as
>> >> >> > if
>> >> >> > they
>> >> >> > are binary is not accurate: hard private through
>> >> >> > module/function/block
>> >> >> > scope
>> >> >> > already exists, it is just difficult to work with in the context
>> >> >> > of
>> >> >> > shared
>> >> >> > prototypes — one must either use WeakMaps, technically giving
>> >> >> > _hardness_
>> >> >> > because of the forgeability of `global.WeakMap` /
>> >> >> > `WeakMap.prototype`
>> >> >> > /
>> >> >> > `WeakMap.prototype.get|has|set`, or be willing to either not worry
>> >> >> > about
>> >> >> > garbage collection or implement it manually. This could be solved
>> >> >> > for
>> >> >> > with a
>> >> >> > few rather undramatic changes, though.
>> >> >> >
>> >> >> > Notably, the first post there lists the following as a
>> >> >> > disadvantage
>> >> >> > of
>> >> >> > the
>> >> >> > soft model it describes:
>> >> >> >
>> >> >> >> Platform objects, both within ECMAScript and in embedding
>> >> >> >> environments,
>> >> >> >> contain hard private state. If a library wants to be
>> >> >> >> high-fidelity
>> >> >> >> and
>> >> >> >> just
>> >> >> >> like a platform object, soft-private state does not provide this
>> >> >> >> (@domenic)
>> >> >> >
>> >> >> > ...but neither model there quite covers that use case. Platform
>> >> >> > objects
>> >> >> > _can_ see each other’s private state (cf the `isView` example
>> >> >> > earlier,
>> >> >> > or
>> >> >> > scan the DOM API specs / Chrome source a bit to find numerous
>> >> >> > examples).
>> >> >> > It’s only the ES layer interacting with their interfaces that
>> >> >> > cannot.
>> >> >> >
>> >> >> > Such things can be achieved with ordinary scope, which is why the
>> >> >> > WeakMap
>> >> >> > pattern has worked in practice in my experience to date, while
>> >> >> > class-declaration-scoped privacy has not. It isn’t uncommon for a
>> >> >> > library’s
>> >> >> > exposed interface to be composed of an object graph, where privacy
>> >> >> > is
>> >> >> > a
>> >> >> > concern at this public interface level, but library internal state
>> >> >> > may
>> >> >> > be
>> >> >> > interconnected in unexposed ways under the hood. The most familiar
>> >> >> > example
>> >> >> > of this is a DOM node tree. As an experiment, perhaps try to
>> >> >> > implement
>> >> >> > the
>> >> >> > relationships between HTMLFormElement, HTMLFormControlsCollection
>> >> >> > and
>> >> >> > the
>> >> >> > various form control elements using either the main private fields
>> >> >> > proposal
>> >> >> > or your alternative proposal and see what happens.
>> >> >> >
>> >> >> >> However, the guardian logic tries to verify that the function
>> >> >> >> trying
>> >> >> >> to
>> >> >> >> access the private fields of an instance is a member of the same
>> >> >> >> or
>> >> >> >> descending prototype that was used to create that instance.
>> >> >> >
>> >> >> > Because I’m looking at this in terms of slots, I’d first point out
>> >> >> > that
>> >> >> > prototypes don’t determine slottedness, the execution of some
>> >> >> > specific
>> >> >> > constructor does. It’s during this process that slots are
>> >> >> > associated
>> >> >> > with
>> >> >> > the newly minted object by its identity. But even the current
>> >> >> > private
>> >> >> > fields
>> >> >> > proposal tracks this behavior closely, and I’m not sure how else
>> >> >> > it
>> >> >> > could
>> >> >> > work. The [[Prototype]] slot of an object is typically mutable
>> >> >> > (`R|O.setPrototypeOf`, `__proto__`) and forgeable (Proxy’s
>> >> >> > `getPrototypeOf`
>> >> >> > trap). Why/how would its value matter when it comes to accessing
>> >> >> > private
>> >> >> > state?
>> >> >> >
>> >> >> > ```js
>> >> >> > const pattern = /foo/;
>> >> >> > Reflect.setPrototypeOf(pattern, Date.prototype);
>> >> >> > pattern instanceof Date; // true
>> >> >> > pattern instanceof RegExp; // false
>> >> >> > pattern.getMinutes(); // throws TypeError because [[DateValue]]
>> >> >> > slot
>> >> >> > is
>> >> >> > missing
>> >> >> > RegExp.prototype.exec.call(pattern, 'foo'); // works; object has
>> >> >> > RegExp
>> >> >> > private slots
>> >> >> > ```
>> >> >> >
>> >> >> >> If I removed that requirement, it would work. However, there'd be
>> >> >> >> no
>> >> >> >> way
>> >> >> >> to keep the private data from being leaked. Sadly, it's all or
>> >> >> >> nothing
>> >> >> >> with
>> >> >> >> this approach. Hard private or soft private, those are the only
>> >> >> >> choices.
>> >> >> >
>> >> >> > In the context of what you’ve described here this may be true, but
>> >> >> > no
>> >> >> > such
>> >> >> > limitation presently exists. We can already do all this — hard,
>> >> >> > leak-free
>> >> >> > privacy, brandedness, “friends” etc — with scopes and WeakMaps,
>> >> >> > but
>> >> >> > for
>> >> >> > the
>> >> >> > fact that the `WeakMap` intrinsics may be forged. So what’s
>> >> >> > baffled
>> >> >> > me
>> >> >> > is
>> >> >> > this: why are all the proposals exploring this space not
>> >> >> > addressing
>> >> >> > that
>> >> >> > relatively simple existing problem, and instead starting off from
>> >> >> > a
>> >> >> > place of
>> >> >> > significant new complexity? You said “maybe after the private
>> >> >> > fields
>> >> >> > problem
>> >> >> > has been resolved, someone will figure out a better way to handle
>> >> >> > your
>> >> >> > use
>> >> >> > cases,” but I’d have hoped for the opposite — I want the primitive
>> >> >> > building
>> >> >> > blocks which things like class field syntax could be built over,
>> >> >> > if
>> >> >> > it
>> >> >> > is
>> >> >> > found that they are still necessary once the root issue is solved
>> >> >> > for.
>> >> >> >
>> >> >> >> The main reason the privacy is set on a declaration level is
>> >> >> >> because
>> >> >> >> scope-level inheritance isn't very good for class-oriented
>> >> >> >> inheritance.
>> >> >> >
>> >> >> > Can you explain this more? I’m not sure what’s meant by
>> >> >> > “scope-level
>> >> >> > inheritance” here.
>> >> >> >
>> >> >> >> I don't intend to stop [...]
>> >> >> >
>> >> >> > I very much admire your dedication! I’m also digging the
>> >> >> > discussion.
>> >> >> > I
>> >> >> > think
>> >> >> > we may be representing viewpoints at opposite extremes here, so
>> >> >> > it’s
>> >> >> > an
>> >> >> > interesting contrast, but it also probably means we may be lacking
>> >> >> > some
>> >> >> > context for understanding one another’s angles. I’d be curious to
>> >> >> > hear
>> >> >> > more
>> >> >> > about what you see as the problems with the current fields
>> >> >> > proposal +
>> >> >> > how
>> >> >> > your members proposal would solve them; the repo readme didn’t
>> >> >> > seem
>> >> >> > to
>> >> >> > include a rationale section.
>> >> >> >
>> >> >> > On Sat, Jul 28, 2018 at 10:30 PM Ranando King <kingmph at gmail.com>
>> >> >> > wrote:
>> >> >> >>
>> >> >> >> I've almost given up on making any significant headway in either
>> >> >> >> adjusting
>> >> >> >> or flat-out correcting the flaws in that proposal, but I don't
>> >> >> >> intend
>> >> >> >> to
>> >> >> >> stop trying until either we get stuck with that proposal, or they
>> >> >> >> understand
>> >> >> >> and accept what I'm telling them, or logically prove that my
>> >> >> >> concerns
>> >> >> >> are
>> >> >> >> either irrational or inconsequential.
>> >> >> >>
>> >> >> >> > Private object state in particular is only _made complex_ by
>> >> >> >> > associating
>> >> >> >> > it with declarations instead of scopes that happen to contain
>> >> >> >> > declarations
>> >> >> >> > (or into which constructors are passed, etc). The complexity is
>> >> >> >> > artificial —
>> >> >> >> > not a good sign imo.
>> >> >> >>
>> >> >> >> That's not quite right. What you're essentially asking for is a
>> >> >> >> violatable
>> >> >> >> private field, or as has been described by others, a "soft
>> >> >> >> private".
>> >> >> >> Since
>> >> >> >> we agree that the "friendly" & "befriend" pair is a somewhat (if
>> >> >> >> not
>> >> >> >> completely) bad idea, I'm going to take 1 more pass at your 3
>> >> >> >> requests
>> >> >> >> with
>> >> >> >> a different angle.
>> >> >> >>
>> >> >> >> > Adding the same “slot” to multiple classes which don’t inherit
>> >> >> >> > from
>> >> >> >> > each
>> >> >> >> > other
>> >> >> >> > Selectively sharing access to private state through functions
>> >> >> >> > declared
>> >> >> >> > outside the class body
>> >> >> >>
>> >> >> >> ```js
>> >> >> >> //Using my proposal
>> >> >> >> var {A, B, C} = (() => {
>> >> >> >>   const common = Symbol("common");
>> >> >> >>
>> >> >> >>   class A {
>> >> >> >>     private [common] = 1;
>> >> >> >>     add(...args) {
>> >> >> >>       var retval = this#[common];
>> >> >> >>       for (let obj of args) {
>> >> >> >>         retval += obj#[common];
>> >> >> >>       }
>> >> >> >>       return retval;
>> >> >> >>     }
>> >> >> >>   }
>> >> >> >>   class B {
>> >> >> >>     private [common] = 2;
>> >> >> >>     optional() {
>> >> >> >>       console.log(`common member = ${this#[common]}`);
>> >> >> >>     }
>> >> >> >>   }
>> >> >> >>   var C = {
>> >> >> >>     private [common]: 3,
>> >> >> >>     required() {
>> >> >> >>       console.log(`common member = ${this#[common]}`);
>> >> >> >>     }
>> >> >> >>   }
>> >> >> >>
>> >> >> >>   return { A, B, C };
>> >> >> >> })();
>> >> >> >>
>> >> >> >> //So you want the following statement to not throw a TypeError
>> >> >> >> and
>> >> >> >> return
>> >> >> >> 6
>> >> >> >> (new A()).add(new B(), C);
>> >> >> >> ```
>> >> >> >> I'm not sure I can make this work in my proposal, and I'm
>> >> >> >> absolutely
>> >> >> >> sure
>> >> >> >> you'd be flatly refused by the other proposal. If a `Symbol` is
>> >> >> >> provided as
>> >> >> >> the `[[IdentifierName]]` of a private or protected field, then I
>> >> >> >> can
>> >> >> >> let
>> >> >> >> that `Symbol` be both the key and value that are added to the
>> >> >> >> `[[DeclarationInfo]]` and `[[InheritanceInfo]]` records. That way
>> >> >> >> there
>> >> >> >> will
>> >> >> >> be a common private field name usable by all 3 objects. However,
>> >> >> >> the
>> >> >> >> guardian logic tries to verify that the function trying to access
>> >> >> >> the
>> >> >> >> private fields of an instance is a member of the same or
>> >> >> >> descending
>> >> >> >> prototype that was used to create that instance. If I removed
>> >> >> >> that
>> >> >> >> requirement, it would work. However, there'd be no way to keep
>> >> >> >> the
>> >> >> >> private
>> >> >> >> data from being leaked. Sadly, it's all or nothing with this
>> >> >> >> approach.
>> >> >> >> Hard
>> >> >> >> private or soft private, those are the only choices. The TC39
>> >> >> >> board
>> >> >> >> has
>> >> >> >> already decided that what they want new syntax for is hard
>> >> >> >> private.
>> >> >> >>
>> >> >> >> > Adding slots dynamically, e.g. when adding mix-in methods that
>> >> >> >> > may
>> >> >> >> > initialize a new slot if necessary when called, since
>> >> >> >> > subclassing
>> >> >> >> > is
>> >> >> >> > not
>> >> >> >> > always appropriate
>> >> >> >>
>> >> >> >> Because the TC39 board has set their sights on hard private, this
>> >> >> >> will
>> >> >> >> require new syntax like what I suggested earlier Adding private
>> >> >> >> members
>> >> >> >> dynamically would also pose a leak risk if it could be done after
>> >> >> >> the
>> >> >> >> prototype has been fully constructed. The main reason the privacy
>> >> >> >> is
>> >> >> >> set on
>> >> >> >> a declaration level is because scope-level inheritance isn't very
>> >> >> >> good
>> >> >> >> for
>> >> >> >> `class`-oriented inheritance. The `class` keyword was provided to
>> >> >> >> simplify
>> >> >> >> the vertical inheritance model, along with some API to enable
>> >> >> >> inheritance
>> >> >> >> from native objects even without using `class`. The syntax
>> >> >> >> changes
>> >> >> >> for
>> >> >> >> simplifying private field declaration are just an extension of
>> >> >> >> that.
>> >> >> >> Even
>> >> >> >> though it's not unusual for some developers to spend a lot of
>> >> >> >> time
>> >> >> >> working
>> >> >> >> with fringe use-cases, syntax changes are almost always going to
>> >> >> >> be
>> >> >> >> made for
>> >> >> >> the most common use cases first. Maybe after the private fields
>> >> >> >> problem
>> >> >> >> has
>> >> >> >> been resolved, someone will figure out a better way to handle
>> >> >> >> your
>> >> >> >> use
>> >> >> >> cases.
>> >> >> >>
>> >> >> >>
>> >> >> >> On Sat, Jul 28, 2018 at 3:52 PM Darien Valentine
>> >> >> >> <valentinium at gmail.com>
>> >> >> >> wrote:
>> >> >> >>>
>> >> >> >>> > Are you saying you want multiple non-hierarchally related
>> >> >> >>> > classes
>> >> >> >>> > to
>> >> >> >>> > have an instance private field with shared name [...]
>> >> >> >>>
>> >> >> >>> Yeah. This is a hard problem to solve when trying to integrate
>> >> >> >>> private
>> >> >> >>> fields with class syntax, but it’s not a problem at all when
>> >> >> >>> privacy
>> >> >> >>> is a
>> >> >> >>> more generic tool based on scope. This also isn’t a foreign
>> >> >> >>> concept
>> >> >> >>> in
>> >> >> >>> ES:
>> >> >> >>> consider this intrinsic method:
>> >> >> >>>
>> >> >> >>> https://tc39.github.io/ecma262/#sec-arraybuffer.isview
>> >> >> >>>
>> >> >> >>> This method returns true if the argument has the
>> >> >> >>> `[[ViewedArrayBuffer]]`
>> >> >> >>> slot. This slot exists on genuine instances of both
>> >> >> >>> `%TypedArray%`
>> >> >> >>> and
>> >> >> >>> `%DataView%`, but they do not receive these slots by way of
>> >> >> >>> inheritance from
>> >> >> >>> a common constructor. There are similar cases in HTML host APIs.
>> >> >> >>>
>> >> >> >>> > The befriend keyword would allow an object to request
>> >> >> >>> > friendship
>> >> >> >>> > with
>> >> >> >>> > an existing friendly object. I'm not sure this is a good idea,
>> >> >> >>> > though.
>> >> >> >>>
>> >> >> >>> I don’t think it is either, no. It’s too much complexity for too
>> >> >> >>> little
>> >> >> >>> gain. But again, this is achievable “for free” just by divorcing
>> >> >> >>> “private
>> >> >> >>> object state” from class declarations (or object literals). I
>> >> >> >>> would
>> >> >> >>> ask:
>> >> >> >>> what problem is solved by making this a feature of the
>> >> >> >>> declarations
>> >> >> >>> themselves? Does it merit the complexity and the hoop jumping
>> >> >> >>> needed
>> >> >> >>> to
>> >> >> >>> handle edge cases?\*
>> >> >> >>>
>> >> >> >>> \* One person’s edge case; another’s everyday concern haha.
>> >> >> >>>
>> >> >> >>> > The example you gave above still declares the functions in
>> >> >> >>> > question
>> >> >> >>> > inside the class body, so that's not really a solution.
>> >> >> >>>
>> >> >> >>> If you’re referring to the first example, that is a
>> >> >> >>> demonstration
>> >> >> >>> of
>> >> >> >>> what
>> >> >> >>> is possible using the existing stage 3 class fields proposal as
>> >> >> >>> implemented
>> >> >> >>> in Chrome. It isn’t what I want; it’s what’s necessary to
>> >> >> >>> achieve
>> >> >> >>> this
>> >> >> >>> with
>> >> >> >>> the current stage 3 proposed model.
>> >> >> >>>
>> >> >> >>> > Sounds to me like you'd love for class syntax to look like
>> >> >> >>> > this
>> >> >> >>> > [[example with mixin syntax in declaration]]
>> >> >> >>>
>> >> >> >>> Perhaps — it’s interesting for sure! But the pattern that
>> >> >> >>> already
>> >> >> >>> works,
>> >> >> >>> `mixin(Cstr)`, is not presently a source of problems for me.
>> >> >> >>> Private
>> >> >> >>> object
>> >> >> >>> state in particular is only _made complex_ by associating it
>> >> >> >>> with
>> >> >> >>> declarations instead of scopes that happen to contain
>> >> >> >>> declarations
>> >> >> >>> (or
>> >> >> >>> into
>> >> >> >>> which constructors are passed, etc). The complexity is
>> >> >> >>> artificial —
>> >> >> >>> not a
>> >> >> >>> good sign imo.
>> >> >> >>>
>> >> >> >>> >  One thing both proposal-class-fields and
>> >> >> >>> > proposal-object-members
>> >> >> >>> > have
>> >> >> >>> > in common is that the focus is on producing instance-private
>> >> >> >>> > fields.
>> >> >> >>> > All 3
>> >> >> >>> > of the scenarios you presented lay outside of that focus for
>> >> >> >>> > one
>> >> >> >>> > reason or
>> >> >> >>> > another.
>> >> >> >>>
>> >> >> >>> Both the WeakMap solution and the stub concept I provided after
>> >> >> >>> are
>> >> >> >>> more
>> >> >> >>> generic than privacy in either of those proposals. When I say
>> >> >> >>> "object
>> >> >> >>> private state," it’s true that the object in question could be
>> >> >> >>> any
>> >> >> >>> object.
>> >> >> >>> But in practice, any realization of the feature would pertain
>> >> >> >>> chiefly
>> >> >> >>> to
>> >> >> >>> class instances, and the examples I gave, though contrived, do
>> >> >> >>> concern
>> >> >> >>> class
>> >> >> >>> instances. The reason private object state is chiefly an issue
>> >> >> >>> of
>> >> >> >>> class
>> >> >> >>> instances stems directly from the nature of prototype methods
>> >> >> >>> and
>> >> >> >>> accessors,
>> >> >> >>> so if you are not making use of prototypes, you could instead
>> >> >> >>> have
>> >> >> >>> used a
>> >> >> >>> closure+factory directly.
>> >> >> >>>
>> >> >> >>> ---
>> >> >> >>>
>> >> >> >>> In a nutshell, my issue with existing proposals could probably
>> >> >> >>> be
>> >> >> >>> summarized as a concern that they are neither as generic nor as
>> >> >> >>> simple
>> >> >> >>> as
>> >> >> >>> native slots. To be clear, proper “slots” are an internal
>> >> >> >>> concept,
>> >> >> >>> only
>> >> >> >>> observable indirectly — but they are the special sauce
>> >> >> >>> underlying a
>> >> >> >>> number
>> >> >> >>> of behaviors which are presently awkward to achieve in ES code
>> >> >> >>> itself,
>> >> >> >>> and
>> >> >> >>> they are a nice simple model of private object state which is
>> >> >> >>> tantalizingly
>> >> >> >>> close to, but not _exactly_ the same as in two critical ways,
>> >> >> >>> symbol
>> >> >> >>> keyed
>> >> >> >>> properties. That said, “real” slots would continue to have an
>> >> >> >>> advantage with
>> >> >> >>> regard to cross-realm stuff even if private symbol keys existed.
>> >> >> >>>
>> >> >> >>> That such a model is radically simpler — minmax and all that —
>> >> >> >>> feels
>> >> >> >>> very
>> >> >> >>> important to me, but I dunno. I’m not holding my breath for big
>> >> >> >>> changes
>> >> >> >>> here. The current stage 3 proposal seems to be unstoppable; much
>> >> >> >>> smarter /
>> >> >> >>> more important people than me have already tried and failed. :)
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> On Sat, Jul 28, 2018 at 3:14 PM Ranando King <kingmph at gmail.com>
>> >> >> >>> wrote:
>> >> >> >>>>
>> >> >> >>>> In a word... wow. You've got me thinking hard here. Those are
>> >> >> >>>> some
>> >> >> >>>> peculiar use cases, and they do a great job of highlighting why
>> >> >> >>>> someone
>> >> >> >>>> might forego using `class`. One thing both
>> >> >> >>>> proposal-class-fields
>> >> >> >>>> and
>> >> >> >>>> proposal-object-members have in common is that the focus is on
>> >> >> >>>> producing
>> >> >> >>>> instance-private fields. All 3 of the scenarios you presented
>> >> >> >>>> lay
>> >> >> >>>> outside of
>> >> >> >>>> that focus for one reason or another.
>> >> >> >>>>
>> >> >> >>>> > Adding the same “slot” to multiple classes which don’t
>> >> >> >>>> > inherit
>> >> >> >>>> > from
>> >> >> >>>> > each other
>> >> >> >>>>
>> >> >> >>>> I'm a little confused by this one. Are you saying you want
>> >> >> >>>> multiple
>> >> >> >>>> non-hierarchally related classes to have an instance private
>> >> >> >>>> field
>> >> >> >>>> with
>> >> >> >>>> shared name, such that the same private field name refers to a
>> >> >> >>>> distinct and
>> >> >> >>>> separate field on each instance of every such class, but where
>> >> >> >>>> any
>> >> >> >>>> such
>> >> >> >>>> instance can have that field referenced by that shared name
>> >> >> >>>> from
>> >> >> >>>> any
>> >> >> >>>> member
>> >> >> >>>> function of the corresponding classes? (Wow that was wordy to
>> >> >> >>>> write
>> >> >> >>>> out...)
>> >> >> >>>> If this is what you meant, you're describing friend classes.
>> >> >> >>>> The
>> >> >> >>>> top-down
>> >> >> >>>> processing nature of ES makes this a difficult thing to create
>> >> >> >>>> a
>> >> >> >>>> clean
>> >> >> >>>> syntax for without risking leaking the private state or
>> >> >> >>>> fundamentally
>> >> >> >>>> altering how ES is processed. Mutual friendship is even harder.
>> >> >> >>>>
>> >> >> >>>> ... and yet I just thought of a way to do it. By telling you
>> >> >> >>>> this
>> >> >> >>>> I'm
>> >> >> >>>> leaving myself to consider writing a proposal containing 2 new
>> >> >> >>>> keywords:
>> >> >> >>>> `befriend` and `friendly`. I don't know if this can be done
>> >> >> >>>> with
>> >> >> >>>> the
>> >> >> >>>> existing proposal being what it is. However, with my proposal,
>> >> >> >>>> there's a
>> >> >> >>>> chance. The `friendly` keyword would declare that an object is
>> >> >> >>>> prepared to
>> >> >> >>>> share select information with any object that befriends it. The
>> >> >> >>>> `befriend`
>> >> >> >>>> keyword would allow an object to request friendship with an
>> >> >> >>>> existing
>> >> >> >>>> friendly object. I'm not sure this is a good idea, though. This
>> >> >> >>>> means
>> >> >> >>>> that
>> >> >> >>>> any object declared 'friendly' is automatically insecure as all
>> >> >> >>>> it
>> >> >> >>>> takes to
>> >> >> >>>> gain access to the selected members of its private space would
>> >> >> >>>> be
>> >> >> >>>> to
>> >> >> >>>> 'befriend' it.
>> >> >> >>>>
>> >> >> >>>> > Selectively sharing access to private state through functions
>> >> >> >>>> > declared
>> >> >> >>>> > outside the class body
>> >> >> >>>>
>> >> >> >>>> The example you gave above still declares the functions in
>> >> >> >>>> question
>> >> >> >>>> inside the `class` body, so that's not really a solution. If
>> >> >> >>>> the
>> >> >> >>>> example you
>> >> >> >>>> gave actually solves your use case, then what you're asking for
>> >> >> >>>> here
>> >> >> >>>> isn't
>> >> >> >>>> even needed. If, however, that was a bad example, then it
>> >> >> >>>> sounds
>> >> >> >>>> like
>> >> >> >>>> you're
>> >> >> >>>> looking for friend functions. See the previous section.
>> >> >> >>>>
>> >> >> >>>> > Adding slots dynamically, e.g. when adding mix-in methods
>> >> >> >>>> > that
>> >> >> >>>> > may
>> >> >> >>>> > initialize a new slot if necessary when called, since
>> >> >> >>>> > subclassing
>> >> >> >>>> > is not
>> >> >> >>>> > always appropriate
>> >> >> >>>>
>> >> >> >>>> Sounds to me like you'd love for `class` syntax to look like
>> >> >> >>>> this:
>> >> >> >>>>
>> >> >> >>>> ```js
>> >> >> >>>> class [<identifierName1>] [extends <identifierName2>] [mixes
>> >> >> >>>> <identifierName3>[, <identifierName3>[, ...]]] { ... }
>> >> >> >>>> ```
>> >> >> >>>> so that the private fields of the objects in the `mixes` list
>> >> >> >>>> are
>> >> >> >>>> added
>> >> >> >>>> to the set of private fields provided by the `class` definition
>> >> >> >>>> directly.
>> >> >> >>>> That would also require another proposal, but I think that can
>> >> >> >>>> be
>> >> >> >>>> done
>> >> >> >>>> regardless of which instance-private fields proposal gets
>> >> >> >>>> accepted.
>> >> >> >>>>
>> >> >> >>>> On Sat, Jul 28, 2018 at 12:49 PM Darien Valentine
>> >> >> >>>> <valentinium at gmail.com> wrote:
>> >> >> >>>>>
>> >> >> >>>>> To put this another, much briefer way, here’s a hypothetical
>> >> >> >>>>> model
>> >> >> >>>>> for
>> >> >> >>>>> associating private state with objects that would cover me.
>> >> >> >>>>> Privacy
>> >> >> >>>>> would be
>> >> >> >>>>> provided...
>> >> >> >>>>>
>> >> >> >>>>> 1. in the form of symbolic keys whose presence cannot be
>> >> >> >>>>> observed
>> >> >> >>>>> (i.e., they would not be exposed by `getOwnPropertySymbols`)
>> >> >> >>>>> 2. and which have a syntactic declaration so that one can be
>> >> >> >>>>> sure
>> >> >> >>>>> they
>> >> >> >>>>> are really getting private keys (i.e., an api like
>> >> >> >>>>> `Symbol.private()`
>> >> >> >>>>> wouldn’t work)
>> >> >> >>>>>
>> >> >> >>>>> ```
>> >> >> >>>>> const bar = private();
>> >> >> >>>>>
>> >> >> >>>>> // alternatively: const #bar; could be anything so long as
>> >> >> >>>>> it’s
>> >> >> >>>>> syntactic
>> >> >> >>>>>
>> >> >> >>>>> class Foo {
>> >> >> >>>>>   constructor() {
>> >> >> >>>>>     this[bar] = 1;
>> >> >> >>>>>   }
>> >> >> >>>>> }
>> >> >> >>>>>
>> >> >> >>>>> // etc
>> >> >> >>>>> ```
>> >> >> >>>>>
>> >> >> >>>>> The keys would be typeof 'symbol'; the only difference being
>> >> >> >>>>> that
>> >> >> >>>>> they
>> >> >> >>>>> are symbols which are flagged as private when created. They
>> >> >> >>>>> would
>> >> >> >>>>> be
>> >> >> >>>>> permitted only in syntactic property assignments and accesses.
>> >> >> >>>>> Existing
>> >> >> >>>>> reflection utilities would disallow the use or appearance of
>> >> >> >>>>> such
>> >> >> >>>>> symbols
>> >> >> >>>>> both to ensure privacy and to maintain the invariant that they
>> >> >> >>>>> are
>> >> >> >>>>> always
>> >> >> >>>>> simple data properties:
>> >> >> >>>>>
>> >> >> >>>>> ```js
>> >> >> >>>>> Reflect.defineProperty({}, #bar, { ... }); // throws type
>> >> >> >>>>> error
>> >> >> >>>>> Object.getOwnPropertyDescriptors(someObjWithAPrivateSlot); //
>> >> >> >>>>> does
>> >> >> >>>>> not
>> >> >> >>>>> include it
>> >> >> >>>>> foo[bar] = 2; // fine
>> >> >> >>>>> ```
>> >> >> >>>>>
>> >> >> >>>>> This is significantly simpler than what’s in flight both in
>> >> >> >>>>> terms
>> >> >> >>>>> of
>> >> >> >>>>> syntax and mechanics, which makes me suspicious that I’m
>> >> >> >>>>> probably
>> >> >> >>>>> ignoring
>> >> >> >>>>> things that other people find important. However it would
>> >> >> >>>>> bring
>> >> >> >>>>> parity to ES
>> >> >> >>>>> objects wrt being able to implement genuinely private slots in
>> >> >> >>>>> userland with
>> >> >> >>>>> the same flexibility as what is done internally.
>> >> >> >>>>>
>> >> >> >>>>> In total, this entails a new primary expression, a boolean
>> >> >> >>>>> flag
>> >> >> >>>>> associated with symbol values, and an extra step added to
>> >> >> >>>>> several
>> >> >> >>>>> algorithms
>> >> >> >>>>> associated with Object and Reflect.
>> >> >> >>>>> _______________________________________________
>> >> >> >>>>> es-discuss mailing list
>> >> >> >>>>> es-discuss at mozilla.org
>> >> >> >>>>> https://mail.mozilla.org/listinfo/es-discuss
>> >> >> >
>> >> >> >
>> >> >> > _______________________________________________
>> >> >> > es-discuss mailing list
>> >> >> > es-discuss at mozilla.org
>> >> >> > https://mail.mozilla.org/listinfo/es-discuss
>> >> >> >
>> >> >> _______________________________________________
>> >> >> es-discuss mailing list
>> >> >> es-discuss at mozilla.org
>> >> >> https://mail.mozilla.org/listinfo/es-discuss


More information about the es-discuss mailing list