Darien Valentine (2018-07-29T04:23:50.000Z)
valentinium at gmail.com (2018-07-29T04:29:29.401Z)
> 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 up _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.
valentinium at gmail.com (2018-07-29T04:28:55.307Z)
> 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 up _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.
valentinium at gmail.com (2018-07-29T04:27:11.663Z)
> 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.
valentinium at gmail.com (2018-07-29T04:26:51.226Z)
> 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.