Harmony:classes static and private
On Tue, Jun 7, 2011 at 3:15 PM, Kam Kasravi <kamkasravi at yahoo.com> wrote:
In the harmony:classes proposal the following example is provided:
class Monster { // "static" places the property on the constructor. static allMonsters = [];
// "public" declares on the prototype. public numAttacks = 0;
// "private" places it on the private record of the new instance. private health; }
According to the grammar it doesn't appear that static and private are allowed together. That is static private allMonsters = []; would be an error. However I think this is a common use case, for example Monster may wish to implement a constructor based dependency injection pattern as:
class Monster { constructor(name, health) { public name = name; private health = health; Monster.allMonsters.push(this); } static allMonsters = []; }
class YourMammaMonster extends Monster { constructor(name,posse) { super(name, 10); private posse = posse; } set health(value) { private(this).health = value*0.5; } }
In this scenario, Monster would want strong encapsulation of allMonsters. Have the authors considered this use case? Are their alternative patterns to achieve a similar result?
Hi Kam, good example!
In the proposal as it stands, you can achieve this by lexical capture. The following use of "module" is not essential, but it makes the lexical capture pattern a bit more straightforward:
module {
allModules = [];
export class Monster {
constructor(name, health) {
public name = name;
private health = health;
allMonsters.push(this);
}
}
}
We have talked about adding some way to state class-private per-class variable declarations without having to place them textually outside the class. However, a problem with "static private" is that it suggests that such things are properties. They're not. They're just lexically captured variables.
On Jun 7, 2011, at 3:31 PM, Mark S. Miller wrote:
We have talked about adding some way to state class-private per-class variable declarations without having to place them textually outside the class. However, a problem with "static private" is that it suggests that such things are properties. They're not. They're just lexically captured variables.
How could you tell? I mean, what reflection APIs would not disclose static privates as properties?
Since harmony:private_name_objects are in Harmony, it's not a given that static privates must be lexically captured as in a power-constructor pattern. It should not be observable apart from reflection.
From harmony:private_name_objects#open_issues I think we have some freedom to restrict reflection APIs from seeing any private names. That leaves proxies, but with class static private (or should that be private static? ;-)) members, a Proxy can't get in the middle. Can it?
Between the open issues on private name objects and the private(this) placeholder and related open issues on classes, I believe we have some room to maneuver.
My point here is not to argue that we must have static private class members. Only that we could consider them as distinct from lexically captured private upvars a la the power constructor pattern.
I agree with all of this. It does seem bizarre to resort to private names for a use case addressed well by lexically captured variables. But yes, we could do either.
Thanks Mark, Brendan
Within this context subtype access and it's interactions with private would also be of interest to me. For example interactions with static private const.
Yes, there's the rub. "private" != "protected".
/be
Sent from my iPad
On Jun 7, 2011, at 5:24 PM, Kam Kasravi wrote:
ithin this context subtype access
Just a word of terminology caution. Harmony classes are not types and harmony subclassing doesn't make any subtyping guarantees. In a language as dynamic as JavaScript subtyping is definitely not equivalent to subtyping.
On Tue, Jun 7, 2011 at 6:11 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
In a language as dynamic as JavaScript subtyping is definitely not equivalent to subtyping.
Wow, JavaScript is even more dynamic than I thought ;).
Oops, obviously I meant: JavaScript subclassing is definitely not equivalent to subtyping.
Time for dinner-at keyboard too long.
Yes I puzzled over that a bit :)
I realize that types within a typed language need to provide certain guarantees in terms of schema, equivalence, etc. For the those of us more 'untyped' than others, could you expound very briefly on the type vs class distinction? Is it due to javascript's ability to morph a class definition both in terms of its properties and its prototype chain? I also ask due to Dave's suggestion in relation to modules that ES.next is much more amenable to static analysis (paraphrasing) which I would think an IDE would exploit to provide some level of type-checking. In Allen's mirrors article, it seems like types would be important to reflection. Although wouldn't you know, I searched Allen's article (www.wirfs-brock.com/allen/posts/228) and he never once mentions 'type' :)
There are lots of sources about this
The classic but somewhat technical paper that coined the phrase that I misquoted is William Cook's: citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.102.8635&rep=rep1&type=pdf some overviews c2.com/cgi/wiki?SubTypingAndSubClassing another good overview, from more of a java perspectivehttp://www.mit.edu/~6.170/lectures/lect09-subtyping-handouts.pdf
Basically, subtyping typically is taken to imply strict substitutability. An instance of a subtype can be used anywhere an instance of its supertype is expected. This isn't just about what public methods are available (a subtype have can only add to the supertypes interface). It is also about what can be passed to and returned form each method, recursively applied. It is trivial to break such substitutability with JavaScript objects, even those created by the proposed class declarations. It is possible to create JavaScript objects that behave as subtypes but it takes work. It may not always be worth the effort.
Statically typed languages and their users are often very concerned about correct subtyping because the memory safety of such languages often depends upon the fact that subtype substitutability invariants are guaranteed. Dynamic language folks are often less concerned because any such broken invariants will at worst cause the program to perform the wrong computation but dynamic runtime checks will still guarantee memory safety. Your actual milage may vary.
Allen (I am not a type theorists)
Thanks Allen, more than I was hoping for ...
Either I'm out-of-date or the wiki page is. My understanding is that at the TC39 meetings we decided to move instance and private record declarations out of the class body and into the constructor. If that's the case, this should be less confusing. You can no longer use "public" or "private" at the class body level. So that example becomes:
class Monster { // "static" places the property on the constructor. static allMonsters = [];
// No modifier declares on the prototype. numAttacks = 0;
constructor() { // "private" places it on the private record of the new instance. private health; } }
That's better, but "public" and "private" are still less than ideal keywords here since Javascript's use of them is distinctly different from other languages. Alas, they were the best we could come up with.
As far as your original question, Mark is right. You can have private "static" state by just having a variable in the closure that surrounds the class declaration but that isn't otherwise visible. Modules are one way to do that. This is another:
var Monster; { let allMonsters = []; Monster = class { // can access allMonsters here... } }
(Hopefully I have that right.)
On Wed, Jun 8, 2011 at 3:13 PM, Bob Nystrom <rnystrom at google.com> wrote:
That's better, but "public" and "private" are still less than ideal keywords here since Javascript's use of them is distinctly different from other languages. Alas, they were the best we could come up with.
"public" confuses me because its name is related to access control. And because the following doesn't make any sense and I expected to be able to declare a private instance property:
*class *Monster { private public health = 10; }
So, taking a page from CoffeeScript's for own ... in extension, what do you think about this?
*class *Monster {
*private own* health = 10;
*private static *allMonsters = [];
*own *id;
constructor() {
*this*.id = Monster.allMonsters.length;
Monster.allMonsters[this.id] = this;
}
}
Juan
Hmmm... I'm referencing harmony:classes. Is this one incorrect?
You're referencing the correct one, but the committee met recently and changes discussed there may not have made it to the wiki yet.
On Wed, Jun 8, 2011 at 2:11 PM, Kam Kasravi <kamkasravi at yahoo.com> wrote:
Hmmm... I'm referencing harmony:classes. Is this one incorrect?
On Jun 8, 2011, at 11:13 AM, Bob Nystrom <rnystrom at google.com> wrote:
Either I'm out-of-date or the wiki page is. My understanding is that at the TC39 meetings we decided to move instance and private record declarations out of the class body and into the constructor.
Correct. I see the error now. I'll fix. Thanks.
On Jun 8, 2011, at 11:13 AM, Bob Nystrom wrote:
Either I'm out-of-date or the wiki page is. My understanding is that at the TC39 meetings we decided to move instance and private record declarations out of the class body and into the constructor. If that's the case, this should be less confusing. You can no longer use "public" or "private" at the class body level. So that example becomes:
Yes, the proposal puts instance property/variable declarations in the constructor body.
No, it does not outlaw private and even public for class body elements that define (without static or whatever we use instead of static) prototype properties.
Or that was what I intended in rewriting the earlier proposal. Thanks to Mark for fixing whatever was broken.
On Wed, Jun 8, 2011 at 3:40 PM, Brendan Eich <brendan at mozilla.com> wrote:
On Jun 8, 2011, at 11:13 AM, Bob Nystrom wrote:
Either I'm out-of-date or the wiki page is. My understanding is that at the TC39 meetings we decided to move instance and private record declarations out of the class body and into the constructor. If that's the case, this should be less confusing. You can no longer use "public" or "private" at the class body level. So that example becomes:
Yes, the proposal puts instance property/variable declarations in the constructor body.
No, it does not outlaw private and even public for class body elements that define (without static or whatever we use instead of static) prototype properties.
What do they accomplish? I'm guessing private places the property on the private record of the prototype. What does public do?
On Wed, Jun 8, 2011 at 3:41 PM, Brendan Eich <brendan at mozilla.com> wrote:
Or that was what I intended in rewriting the earlier proposal. Thanks to Mark for fixing whatever was broken.
I haven't fixed it yet. Stay tuned.
On Jun 8, 2011, at 4:04 PM, Bob Nystrom <rnystrom at google.com> wrote:
On Wed, Jun 8, 2011 at 3:40 PM, Brendan Eich <brendan at mozilla.com> wrote: No, it does not outlaw private and even public for class body elements that define (without static or whatever we use instead of static) prototype properties.
What do they accomplish? I'm guessing private places the property on the private record of the prototype. What does public do?
No "private record" fiction on a plain old object such as a class prototype. Rather, "private" creates a private name object denoted by the declared name and usable after dot by that name within the class body.
"public" is symmetric longhand for what methods, accessors, and assignments as class body elements do in the proposal.
In the harmony:classes proposal the following example is provided:
class Monster { // "static" places the property on the constructor. static allMonsters = [];
// "public" declares on the prototype. public numAttacks = 0;
// "private" places it on the private record of the new instance. private health; }
According to the grammar it doesn't appear that static and private are allowed together. That is static private allMonsters = []; would be an error. However I think this is a common use case, for example Monster may wish to implement a constructor based dependency injection pattern as:
class Monster { constructor(name, health) { public name = name; private health = health; Monster.allMonsters.push(this); } static allMonsters = []; }
class YourMammaMonster extends Monster { constructor(name,posse) { super(name, 10); private posse = posse; } set health(value) { private(this).health = value*0.5; } }
In this scenario, Monster would want strong encapsulation of allMonsters. Have the authors considered this use case? Are their alternative patterns to achieve a similar result?