!Re: proposal: Object Members

Michael Theriot michael.lee.theriot at gmail.com
Mon Jul 30 05:25:36 UTC 2018


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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180730/8ce7711b/attachment-0001.html>


More information about the es-discuss mailing list