Darien Valentine (2018-07-28T20:52:21.000Z)
> 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
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180728/c1be94ac/attachment-0001.html>
valentinium at gmail.com (2018-07-28T20:55:27.474Z)
> 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. :)