example.myVar = 500 should throw an access error.
You don't need to distinguish because you shouldn't be shadowing private variables.
example.myVar = 500 should throw an access error.
You don't need to distinguish because you shouldn't be shadowing private variables.
That removes a major benefit of private fields (which is to be able to change implementation details without breaking the public interface)
I don't think anyone really loves the syntax, but there doesn't seem to be much of a better way of doing it.
It's not possible to have current code that works like that, so defining new properties for that code (that it can only be used inside the class as a private field) isn't breaking anything.
In other words, outside of the class implementation, `example.#myVar` is always an error, regardless of the existence of a private field or not, and it will always be an error with or without this proposal. And inside the class it's only legal if the private field was defined in the class.
Dynamic property access isn't allowed for private fields, so it kind of side steps that whole issue.
https://github.com/tc39/proposal-class-fields/blob/master/PR...
On one hand I follow a more functional programming style so this won't affect me but on the other I worry about trying to understand other people's code (especially very serious programming [tm]).
>If they are different it's very inconsistent and IMHO a lot worse.
It is called out in the link I posted above as a "downside", and I agree that it sucks, but there aren't any other good options for this without breaking compatibility with current code.
>I worry about trying to understand other people's code
Luckily there is one big benefit to this that makes the impact of the weirdness surrounding the naming much less awful. Because of the "hard encapsulation" that the private fields have, they are literally and explicitly un-viewable, un-accessible, and un-usable outside of the class body.
So the amount of complex meta-programming and many of the reasons you'd want dynamic property access in the first place (iterating, monkey-patching, using arbitrary strings as keys, computed keys, etc...) aren't applicable, and if you really want those features but also with privacy, you can nest a plain object as a private field and work with it that way just the same.
So it may have some gotchas, but because the proposal is intentionally restricted as much as possible, and it explicitly disallows a lot of the metaprogramming that can be common and it only allows a very simple lookup syntax, the weirdness is very well contained, and at worst will be confined to between the opening and closing brace of a `class` statement.
That's not an extreme hypothetical, it was a real example from someone trying to use this feature. They had tried to emulate private fields with an underscore before, people started using the private variables, and now they want to refactor while keeping the current "private-turned-public" variable working the same.
I'm sure you can come up with answers for most of those things, but will they really be easier to understand than the current proposal? I'd hate if I have to look around in the class any time `this.anything` happens to see if it's private, public, shadowed, a getter/setter, etc...
`this.#myVar` is explicit, it's obvious, and even if it's ugly as a sin, you know it's not doing something "normal" right away.
Imagine you are using a library and extending it adding a few properties for usage in your app, and one patch upgrade your app breaks because the `example.tag` stops working because the library decided to add `this.tag` as a private variable.
Imagine React decides to use this, and they add a private `this.internalState`, but all react components are extended from that. So now all react components can't use `this.internalState` and if the react team ever changes the name of the private variables, then it is a breaking change and can cause code to stop working.
You can say "well don't do that" all you want, but a good portion of the web uses techniques like that, and breaking code because you feel they are doing it wrong doesn't make a healthy ecosystem.
What are some of the other languages that interpret "private" as never exposing the existence of that field to a public consumer? Most languages I've used don't expose the _value_ of the field...
See [0] for some info straight from the proposal, but the gist is doing it this way makes it so that you never have to worry about name collisions for private fields. Subclassing, superclassing, and object "monkey patching" all can continue to work as-is with no changes, and none of them have to worry about the existence of private fields complicating implementations, and the classes with private fields can feel free to change and rename them as much as possible, even within patch versions of libraries, since they cannot impact any code outside of the class under any circumstances. That's a pretty powerful guarantee to give which GREATLY simplifies working with them.
If I want to extend the react component class, I don't need to worry that my `#component` private field is going to break if an update to the react component class adds their own `#component` field, or if a user of my library tries to do something like this:
const fancyObj = new FancyObj()
fancyObj.tag = Symbol('tag')
Which I'll admit to having used in some cases where I want to tag a bunch of otherwise identical objects which will be thrown into an array and then be able to easily pluck out the ones I tagged later. Without true encapsulation, that code above would break if they changed the private interface to use the `.tag` field internally, and I would have no idea because it is consitered a private interface and wouldn't need to be documented or maintained across versions.[0] https://github.com/tc39/proposal-class-fields/blob/master/PR...
There is nothing addressed here that can't be solved with composition. This seems like an odd step for an aspiring functional language to take...
Some of that is pushing it in a functional direction, some in a "classic OOP" direction.
Much like classes in the first place, this is a feature added to the language to stop the proliferation of stop-gap solutions and standardize on one implementation for most.
Sure, I won't be using this feature, just like I won't be using classes at all in most cases (React components being one exception), but many will, and if this isn't added, they will continue trying to solve problems with solutions which are more complicated, slower, and buggier than this. All the talk about how it's not the "right" solution doesn't matter.
To use an over-the-top metaphor: People are jumping out of planes, and you aren't going to stop them, so the very least you can do is give them a well tested parachute and a map of where to safely land.
class Base {
private int field;
Base() {
this.field = 1;
}
void baseMethod() {
System.out.println("Base.field = " + field);
}
}
class Derived extends Base {
private int field;
Derived() {
this.field = 2;
}
void derivedMethod() {
System.out.println("Derived.field = " + field);
}
}
public static void main(String[ ] args) {
Derived d = new Derived();
d.baseMethod();
d.derivedMethod();
}
It prints: Base.field = 1
Derived.field = 2 class Base:
def __init__(self):
self.__field = 1
def baseMethod(self):
print("baseMethod " + str(self.__field))
class Derived(Base):
def __init__(self):
super().__init__()
self.__field = 2
def derivedMethod(self):
print("barMethod " + str(self.__field))
d = Derived()
d.baseMethod()
d.derivedMethod()
And it prints: baseMethod 1
barMethod 2
Ruby doesn't really have fields that are private to subclasses, but Ruby also embraces monkey-patching, so that's not entirely surprising."Having a private field named x must not prevent there from being a public field named x, so accessing a private field can't just be a normal lookup. This is only an issue in JavaScript because of its lack of static types. Statically typed languages use type declarations to distinguish the external-public/internal-private cases without the need of a sigil. But a dynamically typed language doesn't have enough static information to differentiate those cases." [0]
There are also performance concerns to changing the lookup logic without the sigil. More info in the link.
0: https://github.com/tc39/proposal-class-fields/blob/master/PR...
Sure, you say, that's because in PHP a public property and a private property cannot have the same name. Correct. Why is this a requirement? What problem is this trying to solve? In e.g. older Python we would use the convention of a leading underscore to indicate that a property is private, even if technically one _could_ access it publicly it was understood that is a bad idea to do in practice. It's not a security issue - in every language one could read the "private" properties by some method or another. Reflection, for instance. Or, back to PHP, by casting the object to an array (I did mention that PHP is the canonical hate-it dynamically-typed language).
The problem is that it seems a "private by convention" system isn't private enough for many library authors, who are finding their private internal methods being used regardless, and then after some time becoming ossified leaving the maintainers in a tough situation. Support the "private" interface even though they shouldn't have to to avoid breaking a significant number of users, or break the "private" interface and leave many developers with code churn.
Regardless of where fault lies (often times it's one library using the private interface of another library, and the developer gets caught in the middle), this is a bad thing, so people began workarounds like complicated closure systems or weird-looking interfaces which emulated true private fields without having support for them.
This started becoming popular enough that it was decided that adding them to the official syntax would be better, and unlike in PHP or other languages, there is no way around it here. Serializing or casting the object doesn't expose private fields, and there is no reflection methods or anything that would allow it. They are truly private.
I personally share your feelings that this isn't an issue that needs solving (i'm of the opinion that the lack of easy truly private properties had a non-zero impact on the rise of javascript, and the ability to tweak private interfaces in your code is a net benefit, even if it gives developers rope to hang themselves with), but the pain felt from it is real for many, and the workarounds they were using were not only slow and difficult to use and maintain, but also very hard to understand, and this alternative is a much better solution in my opinion.
So while I most likely won't be using them, I reluctantly support them being added to the language.
[0] https://github.com/tc39/proposal-class-fields/blob/master/PR...