!Re: proposal: Object Members

Isiah Meadows isiahmeadows at gmail.com
Mon Jul 30 04:42:23 UTC 2018


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