Private names use cases
On 2010-12-20 17:21, Allen Wirfs-Brock wrote:
I've seen mentions in the recent thread that the goal of the "Private Names" proposal was to support "private fields" for objects. While that may be a goal of some participants in the discussion, it is not what I would state as the goal.
I have two specific use cases in mind for "private names":
- Allow JavaScript programmers, who choose to do so, to manage the direct accessibly of object properties. This may mean limiting access to methods of a particular instance, or to methods of the same "class", or to various friends or cohorts, etc.
Indeed, selective visibility is an important goal of both the private names and soft fields proposals.
It's important to note that for strong encapsulation, the code implementing an abstraction must be able to control which other code can see which fields/properties, but code outside the abstraction's scope must not be able to decide this for itself.
I.e. +1 for the ability to simulate visibility mechanisms that meet this criterion, such as Eiffel's export lists, but -1 for the ability to simulate visibility mechanisms that don't, such as C++'s friend declarations.
- Allow third-party property extensions to built-in objects or third-party frameworks that are guaranteed to not have naming conflicts with unrelated extensions to the same objects.
Of these two use cases, the second may be the more important.
Note that I emphasized "properties" rather than a new concept such as "private fields".
I think it is a mistake to emphasize that, since it overspecifies the mechanism. In the soft fields proposal, the fields are not properties, but that makes little or no visible difference to their use.
On 12/20/10, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
I've seen mentions in the recent thread that the goal of the "Private Names" proposal was to support "private fields" for objects. While that may be a goal of some participants in the discussion, it is not what I would state as the goal.
I have two specific use cases in mind for "private names":
- Allow JavaScript programmers, who choose to do so, to manage the direct accessibly of object properties. This may mean limiting access to methods of a particular instance, or to methods of the same "class", or to various friends or cohorts, etc.
If private is based on lexical scope then it's already possible but it can be a bad smell.
For example:
var Blah = function() { var privateBlah = { complicatedDirtyWork : function() { alert("blah.") } }; var Blah = { goBang : function() { privateBlah.complicatedDirtyWork(); } }; return Blah; }(); Blah.goBang()
Great for a one-off, but when you wanna have many of the ADT (many instances of Blah), then there's an equal number of privateBlah and the strategy must make some sort of lookup, e.g.
var delegateBlah = getPrivateBlah( this ); delegateBlah.doTrick();
That's a bit more work and when there are only a couple of fields, it seems like too much trouble.
If it were authored in a way that obviates that cruft but could still be facilitated by using scope tricks, as above?
Coming from the commonjs perspective I did something similar to create private data per instance using a closure. I feed an object literal into a 'type' generator so that:
Type.create('Foo', {
imports: {
log: "require('log')"
},
specification: {
'private': {
bar: null,
baz: null
},
'constructor': function(props) {
try {
var properties = props || {};
bar = properties.bar;
} catch(e) {
log.Logger.error(this,e);
}
return this;
},
'public': {
print: function() {
log.Logger.debug(this,'bar='+this.getBar());
}
}
}
}, require, exports);
generates
// Foo
var Foo = (function() {
// imports
var log = require('log');
// public
Foo.prototype['print'] = function print() {
log.Logger.debug(this, 'bar=' + this.getBar());
};
function Foo() {
// private
function privateData() {
this.bar = null;
this.baz = null;
};
var p_vars = new privateData();
var bar = p_vars.bar;
this.getBar = function getBar() {
return bar;
};
this.setBar = function setBar(b) {
bar = b;
return this;
};
var baz = p_vars.baz;
this.getBaz = function getBaz() {
return baz;
};
this.setBaz = function setBaz(b) {
baz = b;
return this;
};
// constructor
var args = Array.prototype.slice.call(arguments);
arguments.callee.ctor = function(props) {
try {
var properties = props || {};
bar = properties.bar;
} catch(e) {
log.Logger.error(this, e);
}
return this;
};
return arguments.callee.ctor.apply(this, args) || this;
};
return function() {
var args = Array.prototype.slice.call(arguments);
arguments.callee['constructor'] = Foo;
return new Foo(args && args.length && args[0]);
};
})();
exports.Foo = Foo;
the object literal looks a little like the object initializer strawman (strawman:object_initialiser_extensions). The idea is the user is shielded from private data lookup when creating an object instance.
eg
Foo({bar:'hello'}).print(); // internally calls new
Foo({bar:'world'}).print();
On Mon, Dec 20, 2010 at 9:21 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
I've seen mentions in the recent thread that the goal of the "Private Names" proposal was to support "private fields" for objects. While that may be a goal of some participants in the discussion, it is not what I would state as the goal.
I have two specific use cases in mind for "private names":
- Allow JavaScript programmers, who choose to do so, to manage the direct accessibly of object properties. This may mean limiting access to methods of a particular instance, or to methods of the same "class", or to various friends or cohorts, etc.
- Allow third-party property extensions to built-in objects or third-party frameworks that are guaranteed to not have naming conflicts with unrelated extensions to the same objects.
Of these two use cases, the second may be the more important.
I'm glad you agree. By incremental fiddling, such as repairing the encapsulation leaks of private names, perhaps we could brings these two proposals closer together to try to find common ground. However, this second use case would still be a real difference. < strawman:names_vs_soft_fields#conflict-free_object_extension_using_soft_fields>
uses your example of this use case. In light of your message, I just added a note on the crucial difference:
For defensive programming, best practice in many environments will be to freeze the primordials early, as the dual of the existing best practice that one should not mutate the primordials. Evaluating the dynamic behaviour of Python applications crpit.com/confpapers/CRPITV91Holkner.pdf (See
also gnuu.org/2010/12/13/too-lazy-to-type) provides evidence that this will be compatible with much existing content. We should expect these best practices to grow during the time when people feel they can target ES5 but not yet ES6.
Consider if Object.prototype or Array.prototype were already frozen, as they should be, before the code above executes. Using soft fields, this extension works. Using private names, it is rejected.
Note that I emphasized "properties" rather than a new concept such as "private fields". I believe we should be trying to build upon the conceptual foundation of the existing JavaScript object model whenever possible. We should strive to avoid introducing new concepts such as non-property fields into the object model. (see www.wirfs-brock.com/allen/posts/43 for further thoughts on this topic.)
I find this latter point and your elaboration on that web page bizarre. It is the private names proposal that would change the object model, even if you consider these changes minor. The soft fields proposal does not change the object model at all. It has the semantics of a side table.
It seems both of your key points in this message support soft fields over private names.
See below:
On Dec 21, 2010, at 9:03 AM, Mark S. Miller wrote:
On Mon, Dec 20, 2010 at 9:21 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote: I've seen mentions in the recent thread that the goal of the "Private Names" proposal was to support "private fields" for objects. While that may be a goal of some participants in the discussion, it is not what I would state as the goal.
I have two specific use cases in mind for "private names":
- Allow JavaScript programmers, who choose to do so, to manage the direct accessibly of object properties. This may mean limiting access to methods of a particular instance, or to methods of the same "class", or to various friends or cohorts, etc.
- Allow third-party property extensions to built-in objects or third-party frameworks that are guaranteed to not have naming conflicts with unrelated extensions to the same objects.
Of these two use cases, the second may be the more important.
I'm glad you agree. By incremental fiddling, such as repairing the encapsulation leaks of private names, perhaps we could brings these two proposals closer together to try to find common ground. However, this second use case would still be a real difference. strawman:names_vs_soft_fields#conflict-free_object_extension_using_soft_fields uses your example of this use case. In light of your message, I just added a note on the crucial difference:
For defensive programming, best practice in many environments will be to freeze the primordials early, as the dual of the existing best practice that one should not mutate the primordials. Evaluating the dynamic behaviour of Python applications (See also gnuu.org/2010/12/13/too-lazy-to-type) provides evidence that this will be compatible with much existing content. We should expect these best practices to grow during the time when people feel they can target ES5 but not yet ES6.
Consider if Object.prototype or Array.prototype were already frozen, as they should be, before the code above executes. Using soft fields, this extension works. Using private names, it is rejected.
Not everybody in the JavaScript community agrees that this style of defensive programming is desirable or should be a "best practice". On my blog, there was resistance expressed to JavaScript providing any sort of information hiding mechanism. I would not anticipate frozen primordials becoming the norm anytime soon.
Even if this style did become the norm, I don't see why you would argue in support of mechanisms that allow extension of frozen objects. Isn't the whole point of freezing to prevent any extensions. why is the fact that the extension is accomplished using a side-channel any more acceptable to you.
Note that I emphasized "properties" rather than a new concept such as "private fields". I believe we should be trying to build upon the conceptual foundation of the existing JavaScript object model whenever possible. We should strive to avoid introducing new concepts such as non-property fields into the object model. (see www.wirfs-brock.com/allen/posts/43 for further thoughts on this topic.)
I find this latter point and your elaboration on that web page bizarre. It is the private names proposal that would change the object model, even if you consider these changes minor. The soft fields proposal does not change the object model at all. It has the semantics of a side table.
I am speaking of the object model, as perceived to by a JavaScript programmer of moderate skill and also by JavaScript implementors. To me, an incremental extension of a concept that is already present (extending the set of values that can be used as a property name) is a much smaller extension to the object model than the introduction of a new form of per object state (whether called a private field, a soft field, or something else).
The fact that you are proposing implementing you object extension as a look-aside table doesn't mean it isn't a conceptual extension to the object model perceived by JavaScript programmers. That might arguably be the case if you were simply defining a set of conventions based upon Ephemeron tables for decorating objects with additional non-encapsulated state. However, as soon as you tie into either the language's property access syntax ( . and []) as you have (perhaps reluctantly) proposed you have extended the conceptual object model.
It seems to me, the real point of difference here is whether or not we should add a syntactic mechanism that supports information hiding in the context of JavaScript objects. Some constituents want this, others do not.
If you don't care about syntactic support for information hiding than we already have solutions. Ephemeron tables provide a side-band mechanisms for dynamically associating additional state with an objects. You have demonstrated one way to do that in your soft fields proposal. Even without Ephemeron tables, it is already possible to hide state within an object using closure capture.
However, neither of these mechanisms are integrated with the fundamental concept of an "object" that is defined by the language specification and taught to JavaScript programmers. They are based upon coding patterns that assume understanding of difficult concepts (Ephemeron or closure capture). In addition, in the context of current implementations their performance characteristics will be inferior relative to standard property access. If you care about these issues than you probably fall into the camp that wants some sort of syntactic and semantic language extension that explicitly supports object information hiding.
It seems both of your key points in this message support soft fields over private names.
I don't think you even addressed my first point and your argument concerning the second point is based upon an assumption that I don't share regarding a particular "defensive programming" style.
On Tue, Dec 21, 2010 at 10:20 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
See below:
On Dec 21, 2010, at 9:03 AM, Mark S. Miller wrote:
On Mon, Dec 20, 2010 at 9:21 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
I've seen mentions in the recent thread that the goal of the "Private Names" proposal was to support "private fields" for objects. While that may be a goal of some participants in the discussion, it is not what I would state as the goal.
I have two specific use cases in mind for "private names":
- Allow JavaScript programmers, who choose to do so, to manage the direct accessibly of object properties. This may mean limiting access to methods of a particular instance, or to methods of the same "class", or to various friends or cohorts, etc.
- Allow third-party property extensions to built-in objects or third-party frameworks that are guaranteed to not have naming conflicts with unrelated extensions to the same objects.
Of these two use cases, the second may be the more important.
I'm glad you agree. By incremental fiddling, such as repairing the encapsulation leaks of private names, perhaps we could brings these two proposals closer together to try to find common ground. However, this second use case would still be a real difference. < strawman:names_vs_soft_fields#conflict-free_object_extension_using_soft_fields> uses your example of this use case. In light of your message, I just added a note on the crucial difference:
For defensive programming, best practice in many environments will be to freeze the primordials early, as the dual of the existing best practice that one should not mutate the primordials. Evaluating the dynamic behaviour of Python applications crpit.com/confpapers/CRPITV91Holkner.pdf (See also gnuu.org/2010/12/13/too-lazy-to-type) provides evidence that this will be compatible with much existing content. We should expect these best practices to grow during the time when people feel they can target ES5 but not yet ES6.
Consider if Object.prototype or Array.prototype were already frozen, as they should be, before the code above executes. Using soft fields, this extension works. Using private names, it is rejected.
Not everybody in the JavaScript community agrees that this style of defensive programming is desirable or should be a "best practice".
How did "best practice in many environments" become a question of whether "everybody in the JavaScript community agrees" on this, or indeed anything?
On my blog, there was resistance expressed to JavaScript providing any sort of information hiding mechanism. I would not anticipate frozen primordials becoming the norm anytime soon.
How about "a norm"? I can't help feeling that your uses of "everyone" and "the" is an attempt to (in the pejorative sense) strawman the discussion. I am claiming only that it will become a norm, an important one, and one that we should strive to support.
Even if this style did become the norm, I don't see why you would argue in support of mechanisms that allow extension of frozen objects. Isn't the whole point of freezing to prevent any extensions.
No. Let's distinguish two use cases. The point of shallow freezing is to create a "tamper proof object" (the phrase I've been using in talks). If x is a tamper proof object given to otherwise isolated subsystems A and B, then the only interactions between them enabled by giving them x are those that the author of x chooses to provide. This helps both security and modularity. As David-Sarah points out, only if the author of x is in control of what public interface they export can they know what changes they can make without breaking clients.
Building on this, the point of transitive immutability is to create objects that can be safely shared between isolated subsystems without thereby giving them any means to interact. With out historic inability to freeze the primordials (Object.prototype, etc), our only isolation mechanism was the creation of separate frames. In the browser, separate same-origin frames by themselves provides no security benefit, but are increasingly used for their modularity benefit -- to ensure that various complex subsystems do not interfere with each other. Notice that the clone code, whether expressed using soft fields or private names, will not succeed at associating default behavior with objects from other frames. If same-origin frames grows as the best practice, we both lose.
When we are able to freeze the primordials, and combined with our desire to remove the global object from the bottom of the scope chain, then we can arrange to bring separate subsystems into one frame without interference. Then the soft field clone works but the private names clone does not. The private names clone only works if we bring these all into one frame and (by not freezing the primordials) risk that these complex subsystems may destructively interfere with each other silently -- with no diagnostic.
why is the fact that the extension is accomplished using a side-channel any more acceptable to you.
Side channel has a particular technical meaning. This channel is overt, and so is not a side channel.
Note that I emphasized "properties" rather than a new concept such as "private fields". I believe we should be trying to build upon the conceptual foundation of the existing JavaScript object model whenever possible. We should strive to avoid introducing new concepts such as non-property fields into the object model. (see www.wirfs-brock.com/allen/posts/43 for further thoughts on this topic.)
I find this latter point and your elaboration on that web page bizarre. It is the private names proposal that would change the object model, even if you consider these changes minor. The soft fields proposal does not change the object model at all. It has the semantics of a side table.
I am speaking of the object model, as perceived to by a JavaScript programmer of moderate skill
As the comparison page shows, using your examples, the object model for normal vanilla usage is identical.
and also by JavaScript implementors.
The fastpath portion of the two are very similar. Both would place the state in question of the objects being extended and reuse the existing inherited-lookup machinery.
Regarding the fastpath, from the implementor perspective, the two proposals have very similar object models. From the casual programmer perspective, the object models are identical. And from the security and formal semantics perspective, soft fields does not change the existing object model at all.
To me, an incremental extension of a concept that is already present (extending the set of values that can be used as a property name) is a much smaller extension to the object model than the introduction of a new form of per object state (whether called a private field, a soft field, or something else).
The fact that you are proposing implementing you object extension as a look-aside table doesn't mean it isn't a conceptual extension to the object model perceived by JavaScript programmers. That might arguably be the case if you were simply defining a set of conventions based upon Ephemeron tables for decorating objects with additional non-encapsulated state. However, as soon as you tie into either the language's property access syntax ( . and []) as you have (perhaps reluctantly) proposed you have extended the conceptual object model.
For the casual programmer, the change to the object models are identical.
It seems to me, the real point of difference here is whether or not we should add a syntactic mechanism that supports information hiding in the context of JavaScript objects. Some constituents want this, others do not.
If you don't care about syntactic support for information hiding than we already have solutions.
I will answer in a separate email.
Ephemeron tables provide a side-band mechanisms for dynamically associating additional state with an objects. You have demonstrated one way to do that in your soft fields proposal. Even without Ephemeron tables, it is already possible to hide state within an object using closure capture.
However, neither of these mechanisms are integrated with the fundamental concept of an "object" that is defined by the language specification and taught to JavaScript programmers. They are based upon coding patterns that assume understanding of difficult concepts (Ephemeron or closure capture). In addition, in the context of current implementations their performance characteristics will be inferior relative to standard property access. If you care about these issues than you probably fall into the camp that wants some sort of syntactic and semantic language extension that explicitly supports object information hiding.
Syntactic yes. I will no longer argue about which syntax. Semantic, to whom?
- Casual programmer: yup, we have the same one in mind.
- Implementor: yup, again, we have essentially the same small change in mind regarding the fast path.
- Security and formal semantics: All for it, if it actually enhances information hiding over what's possible otherwise.
So to answer your question, yes, I think we're all in essentially the same camp.
It seems both of your key points in this message support soft fields over private names.
I don't think you even addressed my first point
I am not sure what point you are referring to. Do you mean
- Allow JavaScript programmers, who choose to do so, to manage the direct accessibly of object properties. This may mean limiting access to methods of a particular instance, or to methods of the same "class", or to various friends or cohorts, etc.
? Other than terminology, I don't see how the proposals differ in this regard. If the issue is that we call the new state "<adjective> properties"
so that it seems more familiar, fine.
and your argument concerning the second point is based upon an assumption that I don't share regarding a particular "defensive programming" style.
What assumption is that? If the assumption in question is whether "everyone" agrees that defensive programming should be "the norm", then I don't share that assumption either.
On 2010-12-21 18:20, Allen Wirfs-Brock wrote:
Even if this style did become the norm, I don't see why you would argue in support of mechanisms that allow extension of frozen objects. Isn't the whole point of freezing to prevent any extensions. why is the fact that the extension is accomplished using a side-channel any more acceptable to you.
That's straightforward: adding an association to an object in a side table in no way breaks the encapsulation of that object. (If it did, then WeakMaps or any simulation of them would also break encapsulation, which is not the case.)
Note on terminology: a "side channel" is a channel by which sensitive information is unintentionally leaked from some operation to potential attackers. This has no relation to a "side table".
Note that I emphasized "properties" rather than a new concept such as "private fields". I believe we should be trying to build upon the conceptual foundation of the existing JavaScript object model whenever possible. We should strive to avoid introducing new concepts such as non-property fields into the object model. (see www.wirfs-brock.com/allen/posts/43 for further thoughts on this topic.)
I find this latter point and your elaboration on that web page bizarre. It is the private names proposal that would change the object model, even if you consider these changes minor. The soft fields proposal does not change the object model at all. It has the semantics of a side table.
I am speaking of the object model, as perceived to by a JavaScript programmer of moderate skill and also by JavaScript implementors.
This is already problematic. The object model is defined by the spec, not by what any particular programmer or implementor perceives.
Soft fields would not extend the object model as defined by the spec at all. That is an objective statement independent of anyone's perceptions.
What a JavaScript programmer of moderate skill will perceive depends on how the feature is explained to them. A good explanation will say both that soft field slots can be viewed as entries in a side table, and that they can be viewed as being stored "with" the key object (and that the latter is likely to be closer to the truth in an optimized implementation, modulo any pointer indirections).
(A minority -- but an important minority -- of programmers will read the spec itself, which will give the side table view normatively, and the other view in a nonnormative NOTE. Other programmers will read interpretations of the spec. Writers of such interpretations will not be able to miss that there are two views; it is possible that they will oversimplify or give bad explanations, but there is not much we can do about that, other than comment on them.)
JS implementors can also be expected to know both views and translate between them as necessary.
To me, an incremental extension of a concept that is already present (extending the set of values that can be used as a property name) is a much smaller extension to the object model than the introduction of a new form of per object state (whether called a private field, a soft field, or something else).
It can be viewed as a form of per-object state, but it's not anything fundamentally "new" that could not be implemented (perhaps inefficiently) in ES5 + WeakMap, or even just ES5.
The fact that you are proposing implementing you object extension as a look-aside table
But that is completely backwards! Mark is proposing to specify the extension that way. Specifications do not dictate implementation.
doesn't mean it isn't a conceptual extension to the object model perceived by JavaScript programmers.
The soft field abstraction is a library feature.
This library feature may, if we decide to do so, be supported by syntax.
The syntax may be what is currently proposed in the private names proposal, or something else.
The syntax proposed in the private names proposal requires extensions to the object model.
Clearly, this does not imply that the soft field abstraction by itself requires extensions to the object model. The combination of the soft field abstraction and the private names syntax does, because the private names syntax does by itself.
That might arguably be the case if you were simply defining a set of conventions based upon Ephemeron tables for decorating objects with additional non-encapsulated state. However, as soon as you tie into either the language's property access syntax ( . and []) as you have (perhaps reluctantly) proposed you have extended the conceptual object model.
Mark has criticized that syntax partly because it depends on extending the object model, and so have I. I intend to propose an alternative syntax, but I'll do that in another post/thread.
I've seen mentions in the recent thread that the goal of the "Private Names" proposal was to support "private fields" for objects. While that may be a goal of some participants in the discussion, it is not what I would state as the goal.
I have two specific use cases in mind for "private names":
Of these two use cases, the second may be the more important.
Note that I emphasized "properties" rather than a new concept such as "private fields". I believe we should be trying to build upon the conceptual foundation of the existing JavaScript object model whenever possible. We should strive to avoid introducing new concepts such as non-property fields into the object model. (see www.wirfs-brock.com/allen/posts/43 for further thoughts on this topic.)