Hacker News new | past | comments | ask | show | jobs | submit login
Implementing Private Fields for JavaScript (hacks.mozilla.org)
52 points by kiyanwang on June 13, 2021 | hide | past | favorite | 50 comments



Are private fields worth all of the problems, as mentioned in article, in a language like JavaScript? Looks like it is cramming in little needed feature with some runtime cost. Also the mental model of private fields does not seem to map to JavaScript constructs very well.

Are there any obvious advantages as vast better JIT performance, etc

Edit: Sounds very confusing and overengineered

> 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.


Private class properties have been highly requested for nearly a decade since classes were first mentioned as a part of ES6, since almost after ES5 was formally published.

This is wanted to make the language more friendly to CS graduates and Java developers who are otherwise not comfortable using the language without the OOP they cannot live without outside this language. As an example, when I have had discussions about this in the past most proponents had no idea how scope works in the language.


I appreciate the context here, though I strongly dislike the reason. One of the values, in my opinion, of learning and working with multiple languages is being exposed to new paradigms and concepts rather than relying on a single approach to solving problems. At its core, javascript is a procedural language, with many functional concepts, and the more we try to hide the prototype-based underpinnings, I think it hurts this growth opportunity.

With that said, JS is a mess in a lot of ways, so maybe this is worthwhile. Hard to know though until it’s too late to revert.

Just my opinion though, I’m curious what others think about this and where I may be missing the mark.


1. Javascript never needed classes. Classes in javascript do not always behave as "cs graduates and java developers" expect, so bugs.

2. Java (and c++) are great examples of class-oriented languages. Javascript is object-oriented.


Yes, if I wanted to write Java then I wouldn’t be writing JavaScript. Not ever. However, I do enjoy JavaScript and part of that enjoyment comes from not writing classes.


I think private fields will come in very handy for libraries. Yes, people should not access fields marked as internal/private, but they often do anyway (at least I've seen it often enough) just because it's the easiest way to fix some issue, or to get more control than the library officially offers. And then they complain when upgrading the library version is a PITA...


I'm unconvinced it's going to matter for libraries. Folks will just use a Babel transform that exposed the private fields somehow (ex. With getters or rewriting the names)


Yeah, I don't get it. Just start the name with a _ and don't allow code that calls it from outside the class.


I don't understand why people are so hyped about OOP syntactic sugar when JavaScript could already do those ages ago. For example: the class keyword. JavaScript could already do classes via factory functions (return an object with associated methods), and factory functions are strictly more powerful than classes because you can declare freestanding variables inside.

And here's the kicker: The freestanding variables that you do declare inside a factory function, those are naturally private fields. You can expose it to the outside world via method closures, but no one else can reach in and modify it directly. Classes can't do that. Functions could. But the general sentiment is to embrace classes and throw factory functions to the wayside, and as a result you need extra effort like implementing private fields for classes when JavaScript functions can already do the same thing.


Because syntactic sugar matters. var x = (function(){})() is just not readable, but it is error prone. The same goes for assigning to __proto__. IMO, the class keyword is a step forward. However, adding # to a variable looks like a step backward. How long before we have this.%x, to mark x "protected"? Or get x() {...} vs set #x()?


Factory functions don't mean using the (admittedly ugly) IIFE syntax or accessing __proto__ fields. This is an example of factory function

    function NewObj(n) {
        let myPublicInt = n;
        let myPrivateInt = 0;

        function privateIncrement() { myPrivateInt++; }

        function incrementPrivateInt() { privateIncrement(); }

        function printPrivateInt() { console.log(myPrivateInt); }

        return {
            myPublicInt,
            incrementPrivateInt,
            printPrivateInt,
        };
    }

    let obj = NewObj(5);
    console.log(obj.myPublicInt); // 5, because myPublicInt is a public field
    console.log(obj.myPrivateInt); // undefined, because myPrivateInt is a private field
    // obj.privateIncrement(); // exception, because privateIncrement is a private method
    obj.printPrivateInt(); // 0
    obj.incrementPrivateInt();
    obj.printPrivateInt(); // 1


so..... how do you know to optimize this as a factory function / "class" in your JS runtime with reusable instructions that just use an instance's scope in order to get good performance and memory usage.... When all that's being spat out is a JS object, that the user could very well modify in the next instruction, 30 instructions time, or conditionally based on some other checks?

And it's still a pretty ugly way of defining a class like object without the syntactics.


But an object constructed from a class still has all the optimisation problems you just mentioned. It’s just syntactic sugar. The optimiser generates invariants which, if invalidated, makes you fall back to a slow path.


The syntactic sugar is something the optimiser is aware of and isn't just a "do this in a more pretty/stylised way" for the developer, it conveys an intent that this is a construct that can be optimized with a certain level of confidence that you can't get from objects that "look like a duck and quack like a duck" if you squint a little.

And if anything happens that does "deoptimize" it, then if we know the "base" is definitely a class, the paths to handle the "deoptimization" can make better decisions and be able to avoid scrapping everything and falling back to the slow path.


JavaScript engines like V8 can already do exactly as you said through hidden classes based on source code position and have been doing so for a long time. I haven't read any evidence that classes are actually better optimized, even if it's often argued as the reason for why classes are better.


"var x = (function(){})() is just not readable, but it is error prone."

How so? I have no trouble reading that, it's certainly clearer than most of the c++ templates I've seen, and error prone? For example?


It's a bit apples and oranges. That declaration doesn't have the power of a C++ template. A C++ class is much simpler.

One of the problems of the style is that you can't easily split it up. Another one is that it allows you to redeclare/reassign x. A third one is that it doesn't tell the reader what it's doing. You'd have to look carefully to find that out. And then there's the "extends" functions, which everyone implements slightly differently. So, for me, the "class" keyword is a positive change that helps overcome JavaScript's dynamic nature a bit.


const x = ... it's usual to read code to understand it "helps overcome JavaScript's dynamic nature", you say that like it's a good thing


Weren't class and const introduced in the same version?

> like it's a good thing

I think so. If you have full control over your own code, and you write in e.g. TypeScript, you don't need it. Otherwise, it can prevent errors that take forever to debug.


The utility of const does nothing to support adding classes to javascript.

TypeScript, also unnecessary and often just a pita.

I've written very much javascript and have never had a bug that took "forever to debug'.

Programmers who like classes, and type-checking, and all the other syntactic sugar should, imo, just use languages that support such things and leave javascript alone.

I learned a lot about programming from the SICP when it first came out. I appreciate and use the good things Scheme inspired in javascript. And with very rare exceptions, such as const, let, and enhancements to builtin objects such as arrays, I still use vanilla js. I create new objects using factory functions and have zero use for classes.

However adding Map, Set, and similar objects to what is essentially the javascript library is fine with me as they do not impact the core syntax of js.


In mid-2000s Microsoft (of all orgs) was actually very opposed to the idea of bringing C++/Java-like classes into Javascript because they have quite an impedance mismatch with prototype-based nature of JS.

I'd say, they were right.


And then MS invented Typescript and it was all classes onward...

I don't really get it either, and I am saying this as someone who codes in both JS and Java. While thinking in OOP concepts comes naturally for me, I found the prototype/function based approach of JS a breeze of fresh air.

I guess the turning point was when JS migrated to the backend and more complex business logic was written in JS. As long as you are basically rendering view state or filtering data, traditional JS is much easier. But write the business logic of some enterprise app, and you want to use the OOP paradigms.


In my opinion, the code was very difficult to read and even harder to understand for !expert javascript devs and even for experts.

For example, I did, what every decent JS developer back then did: you build yet another library ("helper library"), that just abstract these creations away.

So what else is the Class syntax? A helper.

I felt I was one of the very, very rare JS devs, who read "Secrets of a JS Ninja" from John Resig, the jQuery legend, top to bottom multiple times. Afterwards I build very cool stuff, however folks did not understand it with their normale knowledge of JS. It blew me away, that you could do stuff like Function.toString() in combination with RegEx and New Function(). I was awesome, that I could do, what the C# and Java guys could do. I just took a lot more code to achieve. Fast forward 10 years.

I am extremely glad, that TypeScript came a long. It makes collaboration so much more meaningful.

I still love the JavaScript ECMA5 stuff, however the tradeoff was too big. It is like staying with C instead of Python, Java, or DSLs.

Even "You might not need jQuery" ended up being pointless in regards to readability. Why write 20 lines of code, when you can put it in one line? Paradoxically Resig's jQuery had to do a lot of complex stuff to achieve the beauty of $(). So why not simply write Class?

Just my opinion.


I'm still miffed that private fields are not marked with `private`. Can't remember the reasons though.



Not convincing. When you add a new feature, you can change the parser. So internally, you could rewrite every usage of this.x to this.#x (or anything else) upon reading it.

Edit: wrt encapsulation, will the proposed solution work when a class marks the same field private as the one it extends?


Breaking this.x being equivalent to this['x'], and making this.x quietly change its meaning depending on where the function containing it is located and on the presence or absence of a private field with a corresponding name, seems confusing.


I'm surprised they're adding private fields when symbols already exist? Is it just for improved convenience?


Object properties defined as Symbols (even through classes) are still accessible by e.g. Object.getOwnPropertyDescriptors(myObject)

Before the private fields, it was possible to create private properties through a WeakMap object which is somewhat clumsy and not very performant.


Insanely ugly syntax, which breaks the cleanness of JavaScript! I don't buy their rationale - JavaScript is not the only language with private fields, but one of the few it decided to use meaningless prefixes!


I'm wondering if this should be made part of the runtime at all, and not instead e.g. enforce this by JS compilers/minifiers/style checkers: this is something that's relevant at development time, but not at runtime


I agree. Given we already have this in Typescript it seems of little benefit to add it as a runtime feature.


I don’t believe in private variables/fields.

They shouldn’t be used or implemented.

A waste of time and effort.


Hopefully they come up with something better than a # prefix for identifying private fields. It seems like a small thing, but it looks clunky and arbitrary. Even _ would be better, but best of all would be adding a keyword or something instead of using a glyph.


For some time, there was a trend of adding _ to property and method names to indicate “I’m pretending to be private, don’t use me” (I think this happens in several languages, but I only know JS well).

I suspect there’s a risk that if the committee standardised on _ rather than #, it would actually break a load of older apps and content. There’s a good chance the _convention was abused in those earlier codebases.


> `_` would cause compatibility issues with existing JavaScript code, which has allowed `_` at the start of an identifier or (public) property name for a long time. -- https://github.com/tc39/proposal-private-fields/blob/master/...


Why can’t they just introduce a new private keyword, i.e. private let myVar = 0;


The proposal doesn’t even know.


As far as I know it's the standard way in Python.


The # symbol denoting private fields has already been finalized and approved to be a legal part of the language. No going back.



One more reason to just use Typescript.


Variables are never truly private in the compiled JS though. You can fake it using clever closure techniques but there are still ways to access the vars as I understand it. This is fixing that at the JS level.


I don’t know of any way of accessing lexically bound variables that are captured by a closure if there is no explicit getter.


Typescript is a mostly superset of javascript. Typescript does/will also support # for private fields so it changes absolutely nothing.


Better would be priv.


This is exactly what I came up with, too, because it follows "constant => const" analogy. Why are constants not "$name" using the same perverted logic?!


Yes, _ is much better given its precenses in other languages. I would associate # with a number or a link.


The semantic meaning of "#name" is not private. In fact, the "_" is much more meaningful than "#", which is always used as in the meaning of "number" or "index".


I wish they would just leave javascript alone and continue with java or c# or c++ or whatever it is they are trying to transfrom javascript into.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: