Does private(expr) create a private storage block?
I looked back over the class proposal and found that it indeed leaves this case ambiguous, as you point out. We have also not discussed it in committee or even in separate side discussions in which I participated. I don't have strong feelings about this for non-const classes. For const classes, I think privates should always be declared in the constructor. I would like to be able to always allocate instances of const classes of fixed "shape", i.e., non-configurable / non-extensible, so that users don't have to worry about whether they've enabled the resulting optimizations or whether they have uncaught spelling errors.
For consistency, perhaps we should make similar requirements for privates of non-const classes, but this isn't clear. If you have some arguments one way or another, please post. Thanks.
Hello,
well, (const-classes aside) I am looking at private store as an automatic hidden private name indexed block (too implementation-like look, probably, but helps to grasp the content). This code (horror from the design point, managers don't do real work, but I can not come up with better use case) shows some more aspects of this (as was told, private names should help conflict-less monkey-patching)
class CounterManager { incrementFor (client) { private(client).c++; }
startManage (client) { private(client).c = 0; }
countOf (client) { return private(ciient).c; } }
Yes, I could use private name directly, but this grasps the idea from another point of view. And there may be use cases where instances of a classes want to access private part of another instance of the same class (to do comparision, for example, which is read-only, but maybe there are modifying use cases, too).
So I would propose that:
- if private(foo) is used to read a property value, it should silently return undefined is there is no private block (with private name of the actual scope) in foo
- if private(foo) is used to write a value into a property, it should try to create private block (with name for the actual scope) if it does not exist and then write to it
The latter also solves the const-class instances simply - it is not possible to create such block for them, so it fails the same as any other attempt to add propoerty to a frozen object.
But it is matter of point of view, mainly, what is private about? I like broader views, if possible, so I see private as "privately scoped naming for the use of class methods (as they see fit)" than "a way to make field in instance only visible to method of a class" (which is, by the nature of its formulation, imho much harder to implement because of all the constraints it puts on it; general is often better).
Herby
-----Pôvodná správa---
Hello,
Mark S. Miller wrote:
... I don't have strong feelings about this for non-const classes. For const classes, I think privates should always be declared in the constructor. I would like to be able to always allocate instances of const classes of fixed "shape", i.e., non-configurable / non-extensible, so that users don't have to worry about whether they've enabled the resulting optimizations or whether they have uncaught spelling errors.
It is written in class proposal:
- An efficient implementation. The private state should be allocated with the instance as part of a single allocation, and with no undue burden on the garbage collector.
- The ability to have private mutable state on publicly frozen objects.
Now it is the question, what does it say about "fixed shape". Does "fixed shape" mean no private can be added / deleted, but private properties themselves can be mutated? Or is it the weaker "the private space must be created and is not removable (in frozen object), but it is itself extensible and private properties are configurable and writable"?
For consistency, perhaps we should make similar requirements for privates of non-const classes, but this isn't clear. If you have some arguments one way or another, please post. Thanks.
I have more thoughts on this, even the proposal how to make it work dynamically for non-const classes and "fixed" in const classes, but the answer to previous question seems important.
I presume the answer is "the latter", since "with no undue burden on the garbage collector" could be read as "if possible, blended in single object". But I would like to hear from you.
On Thu, Jan 19, 2012 at 1:00 PM, Herby Vojčík <herby at mailbox.sk> wrote:
Hello,
Mark S. Miller wrote:
... I don't have strong feelings about this for non-const
classes. For const classes, I think privates should always be declared in the constructor. I would like to be able to always allocate instances of const classes of fixed "shape", i.e., non-configurable / non-extensible, so that users don't have to worry about whether they've enabled the resulting optimizations or whether they have uncaught spelling errors.
It is written in class proposal:
- An efficient implementation. The private state should be allocated with the instance as part of a single allocation, and with no undue burden on the garbage collector.
- The ability to have private mutable state on publicly frozen objects.
Now it is the question, what does it say about "fixed shape". Does "fixed shape" mean no private can be added / deleted, but private properties themselves can be mutated? Or is it the weaker "the private space must be created and is not removable (in frozen object), but it is itself extensible and private properties are configurable and writable"?
For consistency, perhaps we should make similar requirements for
privates of non-const classes, but this isn't clear. If you have some arguments one way or another, please post. Thanks.
I have more thoughts on this, even the proposal how to make it work dynamically for non-const classes and "fixed" in const classes, but the answer to previous question seems important.
I presume the answer is "the latter", since "with no undue burden on the garbage collector" could be read as "if possible, blended in single object". But I would like to hear from you.
For const classes specifically, my intention is that the "private state" object is "sealed", i.e., it is non-extensible and all its properties are non-configurable, but generally writable unless declared otherwise.
Mark S. Miller <mailto:erights at google.com> January 19, 2012 2:38 PM
For const classes specifically, my intention is that the "private state" object is "sealed", i.e., it is non-extensible and all its properties are non-configurable, but generally writable unless declared otherwise.
Hi Mark, just to clarify: we don't want any observable private state object in any revised classes proposal. It may be that the current proposal is a bit out of date on this, just in terms of terminology and its possible misinterpretation.
I think private specs are a bit weak right now ... or maybe I did not get them properly ...
- what's the expected behavior with mixins ( borrowed method from different classes ) ?
- what if Object.create(objectWithPrivates, descriptor) ? would descriptor methods be able to invoke objectWithPrivates.method() with private(this) access in the function body? If yes, would that private(this) refer to the objectWithPrivates? This would violate the objectWithPrivates private concept, isn't it?
- are privates exportable? method() {return private(this)}
- are private properties, not private anymore once extracted, exportable? method(){return private(this).whatever}
- what about a single block in the Class definition such private {c, i = 0, storage = {}, whatever} so that these are pre defined in a single place and callable across the class scope without requiring usage of private(this) but bound to the current context rather than shared across all instances?
More may come up soon :-)
br
Please read the disclaimers: the private(this) syntax is not going to be adopted, ever; private name objects and freeze details have been worked out separately; the classes proposal is out of date.
Mark S. Miller wrote:
For const classes specifically, my intention is that the "private state" object is "sealed", i.e., it is non-extensible and all its properties are non-configurable, but generally writable unless declared otherwise.
Ok, so I present the concerns and then the proposed solutions.
Concern I. An efficient implementation. The private state should be allocated with the instance as part of a single allocation, and with no undue burden on the garbage collector. (from the class proposal)
(the quote above is also part of this concern)
Concern II. The ability to have private mutable state on publicly frozen objects. (from the class proposal)
I went as far as thinking of blending private state with the object itself when possible (instances of const classes seemed to be such), but this invalidates such optimization (unless freeze would magically left private state writable).
Concern III. The ability to use private(foo) on any object and defining private stqte lazily, if not present. (me)
Concern IV. No need for 'private foo [= bar];' construct, ability to use 'private(this).foo = bar | null;' instead having same outcome. (me)
Concern V. We don't want any observable private state object in any revised classes proposal. It may be that the current proposal is a bit out of date on this, just in terms of terminology and its possible misinterpretation (Brendan Eich's reply to this thread)
Solution. 0. Define prvName as Name.create() for internal use of the private keyword inside the class code.
- Let 'private foo;' in construct be sugar for 'private(this).foo = void 0;'.
- Let 'private foo = bar;' in construct be sugar for 'private(this).foo = bar;'.
- Read access to private(foo).bar should
- check if foo[prvName] exists
- if not, return undefined
- if yes, return foo[prvName].bar
- Write access to private(foo).bar should
- check if foo[prvName] exists
- if not, try to foo[prvName] = null <| {} (may raise errors)
- do foo[prvName].bar = valueToBeWritten (may raise errors)
The errors in 4. are fine - the former means the object is not extensible, so lazy private state cannot be created, but it is semantically ok; the latter means the private state itself is not extensible or the property itself is read-only.
Why it works for const classes: It creates those properties in private state, which are written (declaration is desugared to write) in constructor. Then, the instance is frozen/sealed and the private state is sealed.
Concern I: OK. Maybe smart compiler can do static analysis of the constructor code and create the object prefilled. But I think developer can do this as well, hinting nicely to the compiler by code like:
class Foo { constructor () { ... private(this).{ // all or majority of the private data } ... } ... }
Concern II: Freezing object does not make private state itself frozen. OK.
Concern III: Solved by lazy creation of private state.
Concern IV: Solved by desugaring, making the cases identical, enabled by lazy creation.
Concern V: prvName is not visible, private names are not in key list.
-- Cheers, --MarkM
Herby
P.S.: I posted another thread with proposal for shortcut for private(this), but it still did not reach the list (I see private(this) as non-elegant, too).
On Fri, Jan 20, 2012 at 1:05 AM, Herby Vojčík <herby at mailbox.sk> wrote:
P.S.: I posted another thread with proposal for shortcut for private(this), but it still did not reach the list (I see private(this) as non-elegant, too).
-1 to private(this) here too ... but specs are outdated so maybe it's already private.{definition} in the constructor which imo would look more elegant
Andrea Giammarchi wrote:
On Fri, Jan 20, 2012 at 1:05 AM, Herby Vojčík <herby at mailbox.sk <mailto:herby at mailbox.sk>> wrote:
P.S.: I posted another thread with proposal for shortcut for private(this), but it still did not reach the list (I see private(this) as non-elegant, too).
-1 to private(this) here too ... but specs are outdated so maybe it's already private.{definition} in the constructor which imo would look more elegant
Exactly that syntax is in my not-yet-on-the-list proposal (private.whatever instead of private(this).whatever).
as a reference could replace "this" for privates and would make even reading code easier ... private(this) as concept is OK but in practice is misleading quite a lot ( looks an invoke unrelated with "unique" current object as argument )
+1 then for private.whatever
I can answer how I understood, but I am not the proposer...
Andrea Giammarchi wrote:
- what's the expected behavior with mixins ( borrowed method from different classes ) ?
Each class has its own private scope, that is, private in borrowed method is in different "plane of existence" than private in actual class.
- what if Object.create(objectWithPrivates, descriptor) ? would descriptor methods be able to invoke objectWithPrivates.method() with private(this) access in the function body? If yes, would that private(this) refer to the objectWithPrivates? This would violate the objectWithPrivates private concept, isn't it?
Let the object created is foo. When calling foo.method(), it is accessing private(foo), not private(objectWithPrivates), since this is foo. "If yes" does not happen. Errors may happen since foo probably does not have private space (my proposal in this thread is touching this issue).
- are privates exportable? method() {return private(this)}
Not (if not throwing error, it should simply return this).
- are private properties, not private anymore once extracted, exportable? method(){return private(this).whatever}
This works as expected. This does not mean it is not private. It is readable via method, but not settable, so it still a private property, but with value published.
- what about a single block in the Class definition such private {c, i = 0, storage = {}, whatever} so that these are pre defined in a single place and callable across the class scope without requiring usage of private(this) but bound to the current context rather than shared across all instances?
I did not understand this question.
On Fri, Jan 20, 2012 at 2:24 AM, Herby Vojčík <herby at mailbox.sk> wrote:
Let the object created is foo. When calling foo.method(), it is accessing private(foo), not private(objectWithPrivates), since this is foo. "If yes" does not happen. Errors may happen since foo probably does not have private space (my proposal in this thread is touching this issue).
Object.create accept the proto and a descriptor, I am not sure a descriptor will/should ever have a private(this) configured unless there is not a class for the descriptor but the list of configurations won't make much sense, i.e.
{value: function () { this instanceof OuterClass /* not possible, it's just an object */ }}
I did not understand this question.
similar to what you are thinking about private.{prop} ... you answered already
thanks and br
Sorry, misunderstood the question.
Andrea Giammarchi wrote:
On Fri, Jan 20, 2012 at 2:24 AM, Herby Vojčík <herby at mailbox.sk <mailto:herby at mailbox.sk>> wrote:
Let the object created is foo. When calling foo.method(), it is accessing private(foo), not private(objectWithPrivates), since this is foo. "If yes" does not happen. Errors may happen since foo probably does not have private space (my proposal in this thread is touching this issue).
- what if Object.create(objectWithPrivates, descriptor) ? would descriptor methods be able to invoke objectWithPrivates.method() with private(this) access in the function body? If yes, would that private(this) refer to the objectWithPrivates? This would violate the objectWithPrivates private concept, isn't it?
Object.create accept the proto and a descriptor, I am not sure a descriptor will/should ever have a private(this) configured unless there is not a class for the descriptor but the list of configurations won't make much sense, i.e.
{value: function () { this instanceof OuterClass /* not possible, it's just an object */ }}
It is an error to use private keyword outside the class block. So, no extension with private(this) using methods at all outside it. If aforementioned Object.create would appear inside class block, then according to actual state of the proposal, as I understand it, it is an error to use private keyword, too. It can only be used in methods (and constructor). But with I am less sure. My proposal is to make use of private keyword much more liberated, in that case if your Object.create would appear inside (any) class block, it would work and added (that class's whose the class block is) private access, outside class block it would not.
Hello,
the current class proposal (as I read it) specifies that the private block is created by first 'private foo[ = "bar"];' in the constructor. The question is, what is constructor does not contain any private declarations, but uses private, like this:
class Coutner { constructor () { this.reset(); }
increment () { private(this).c++; }
reset () { private(this).c = 0; }
get count () { return private(this).c; } }
The reset method is part of the API. Conveniently, it resets the state of the object to the initial state, so constructor is calling it. The question is: does private(this) create the private storage block in this case?