So far, private fields are introduced as follows:
class MyClass {
#privateField = 123;
}
I’d like to propose a small extension: scoped private fields.
The following style is becoming popular in the JavaScript world. It benefits from scoped privacy:
private #data;
function createStringBuilder() {
return {
#data: '',
};
}
function add(sb, str) {
sb.#data += str;
}
function toString(sb) {
return sb.#data;
}
New in this code:
- The keyword
private
in the first line. - The ability to use private fields in object literals.
As a slight downside, you now always need to use the keyword private
:
class StringBuilder {
private #data = ''; // keyword is required
add(str) {
this.#data += str;
}
toString() {
return this.#data;
}
}
On the upside, this gives you the freedom to widen the scope of privacy:
private #data;
class StringBuilder {
#data = ''; // no keyword!
add(str) {
this.#data += str;
}
}
function toString(stringBuilder) {
return stringBuilder.#data;
}
Alternative syntax has been proposed:
- Keyword
private
not needed for “normal” private fields. - Two keywords if you want to widen the scope of privacy:
private
andouter
.
Example:
private #data;
class StringBuilder {
outer #data = ''; // keyword is now required
add(str) {
this.#data += str;
}
}
function toString(stringBuilder) {
return stringBuilder.#data;
}
FP example:
private #data;
function createStringBuilder() {
return {
outer #data: '', // keyword is now required
};
}
function add(sb, str) {
sb.#data += str;
}
function toString(sb) {
return sb.#data;
}
I think this proposal is going against the reasons of introducing the
#
symbol as private class accessor. Consider the following example:Now on the other problem.
I personally disagree with
#
symbol and I think that implementing either new symbol or new keyword is same for all platforms (interpreters).As @supertonsky pointed correctly about making those assumptions, I would like to add that those will be same in either way.
I (personally) would implement that as not being able to see those fields from anywhere else than from the same scope it is defined in. With this you can avoid the conflict when some inherited class exposes its field with the same name as the private one in the parent (according to spec it cannot access the private one anyway) and you may be able to extend this behavior to any scope (not just class definition). The only problem is cross-instance access. But from my point of view it only makes sense to use it in places such as
Object.equals(...)
(as illustrated in FAQ) and even when you pass something that has such field and will result into something false-positive only you as a developer are responsible for that mistake not interpreter.I know that this feature is in stage 3 and it's highly unthinkable that would somehow change. But if you want to make this proposal I'm giving you some thoughts and other possible approach.