-
Notifications
You must be signed in to change notification settings - Fork 26.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Underscore prefixes for "private" properties #490
Comments
A bit. The thing about React components is that all methods should be private so we just save ourselves the typing and don't insert the leading underscore. |
What do you mean? If I have e.g. a ref to an element, I can call methods on it just fine. I've seen this used to implement e.g. If you consider this an anti-pattern, it could be useful to add a clarifying comment to say to not do this. There are definitely problems with this pattern - it's not container-safe, for one. |
I am also interested in an explanation to that. Not all methods are "internal" if we consider that we may call a component's method from the parent. Example: parent.jsx
childComponent.jsx
So, what is our general take on this? Do we still write all methods without any underscore? |
👍 Facebook, for example, use this pattern extensively: https://github.com/facebook/relay/blob/v0.4.0/src/container/RelayRootContainer.js |
@taion what about v0.14 |
What about it? |
Personally, I think this pattern is horrifically bad. Things that are not private are not private - sticking an underscore in front of them doesn't make them private, it just lulls you into the false belief that you can make a breaking change without bumping a major version. It's not private if it's accessible in the runtime. If it's private - ie, via closure or WeakMap - no convention or unit tests are needed. If it's not, it's public, and you must test it, and whether you document it or not, it is public and breaking it counts as a breaking change. At that point, using a leading underscore is just fluff, so why would you need a convention for it? |
That's totally fine - I personally don't mind writing my code either way (as long as I can point to a style guide and say that I'm following it). The issue is that this style guide appears to be inconsistent between https://github.com/airbnb/javascript#22.4 and https://github.com/airbnb/javascript/tree/master/react#methods. I don't see how it's possible to follow both. |
React is a special subset - you could follow both by using |
Okay. If that's intentional, I can live with it. |
JS doesn't have privacy. Underscore-prefixed things are just as public as anything else. |
We should probably just remove this section from the main style guide or rephrase it. Same with the React style guide. This whole attachment to "private" is what makes the rules seem confusing. |
Either way would be fine – it's the inconsistency that's galling. Though I'd note again that FB do in fact use leading underscores, real privacy or no 😛 |
…ng as “private properties”. Per airbnb#490 (comment)
…ng as “private properties”. Per airbnb#490 (comment)
…ng as “private properties”. Per #490 (comment)
…ng as “private properties”. Per airbnb#490 (comment)
I'm late to this discussion, but if I drop the underscore, how will my colleagues know to avoid private methods that will change at any point. The absence of underscore indicates any change will be documented with a semver version bump. PS: I export my private methods so they may be unit tested. |
If it's private, it should not be directly tested, nor accessible - only the public API should be tested. If it's exposed, for any reason, it's simply not private anymore, and changing it in a breaking way is simply a semver-major change. |
In principle, yes, but underscores are a widely understood indicator that a variable is "private". You don't walk through a door with a sock on the handle, even if it's unlocked. Since there are no private properties in ES6 classes, how can I indicate "private" methods and properties? This is especially problematic with getters/setters in ES6, since it needs to be stored in a separate variable. // Simplified example
export class User {
get address() { return this._address; }
set address(address) { this._address = address; }
} |
@nicbou "widely understood indicator" isn't the same thing as "language definition". The answer to your question is that there are no private methods and properties, so you can't indicate them - you can't actually have them. This is a limitation slash feature of JS, and the proper solution is usually to architect around it rather than to work around it. (In that example, I'd use |
This might just be a limitation in understanding. Suppose I have I think the concern is that if I store the address field on While I can e.g. use a How do you deal with such cases? Doc comments are fine, but they have the downside that you can't see them unless you actually look at the code, while property names are visible given just an object. |
More briefly, taking your example, how do you indicate that users should probably do |
@taion Given that a |
@taion if your goal is helpful suggestions, then name it |
I don't think it's especially obscure, though – it's a common convention, not just in e.g. Facebook code but also from earlier versions of this guide: https://github.com/airbnb/javascript/tree/eslint-config-airbnb-v1.0.0#22.4. |
@ljharb, I agree that this is not a language definition, but I disagree that we should architect around it when it's clearly a language limitation. Calling a private method In this scenario, there is no perfect solution, only different hacks for JavaScript's limitations, so arbitrarily preventing one commonly used workaround seems odd to me. As for underscore-prefixed variables being obscure, I completely disagree. If it were, you wouldn't set a rule for it, Mozilla wouldn't mention it, and we would not be having this discussion. |
I think it's problematic because it's a common convention - because many people see it and think "private", and it is anything but. Accessible === public === changes to it affect semver. If you are personally confident that you, and all future contributors, will respect this responsibility on a given project, then you are of course most welcome to disable linter rules and/or ignore sections of the guide - but I think it's important that the default, and the general advice, errs on the side of safety and not false promises of privacy. |
👍 on underscores, while stuff may not actually be private that seems irrelevant, the point of privacy in programming is isolation, encapsulation for humans. Insofar as the convention is understood by humans then who cares whether its "really" private or not. The value of the underscore is in signally to users of your code what is and is not the public API. In my experience despite the potential for folks not following the convention, almost no one uses an underscored method or property thinking thats its something that is part of the supported public api of the package |
@jquense node core has, and npm broke them accidentally. This is a HUGE problem in practice. |
well agree to disagree then on that. In practice it's not been a huge problem for anything i've been involved in. Signally is helpful, and imo better than the alternative of accidentally signally that everything is part of your public api, when you support in browsers that don't have a WeakMap, or the Object model doesn't easily allow closures for instance properties. |
@ljharb, that's great, but since there is no readily accessible solution to have private methods/properties in ES6 classes, what would you suggest? Without a usable alternative to underscore-prefixed classes, there really isn't a reason to dismiss them. It seems to me that this rule takes the standard from "best practices" to "high-minded ideals". So far, all of the proposed changes have been about improving coding practices, rather than forcing awkward workarounds for language limitations. In addition, I forgot to mention JSDocs, which has a @Private attribute as an extra layer of don't-do-this-you-dunce for whoever might want to access private attributes. As a compromise, couldn't we raise an error for accessing _variables from another class? |
My suggestion continues to be, design things so you don't need privacy. Comments, JSDoc or otherwise, aren't enforcement any more than an underscore. In JS, it is a bad coding practice to design something that runs into language limitations - in other words, you need to work within the constraints of the language. This rule will not be changing. You're welcome to fork the guide, and/or overwrite linter rules, to fit what makes sense for your project. |
Yes, and I am asking "how?", because there clearly isn't a way to do so with ES6 classes. |
This isn't the proper venue for it, but if you ping me in the gitter channel, I'll be happy to show you how it's easily possible for your example. |
Sure thing! Let's talk about it Monday. The weekend is too short for arguments about code ;) |
@ljharb Your points are very valid and I guess the Javascript Ecosystem has a history of "working around the language" read CoffeeScript, TypeScript, React & JSX etc. But you must agree the leading (and trailing) underscore is pretty much prevalent in the Industry. And there are some more heavyweights too apart from the above. Your point about working with the language is well taken. I personally feel though that this style guide could be better off taking a solid consistent stand throughout. Eg with https://github.com/airbnb/javascript#accessors--no-getters-setters It seems we are encouraging people to go "around" the language and use custom setters like I may be wrong but this seems to be the same issue as the leading underscore/ |
@gaurav21r I believe Polymer is from Google, so your three examples are really just two. Also, someone being a "heavyweight" is a poor reason to make any choice. This style guide does take a solid and consistent stand: do not use ES5 getters/setters; and do not use underscores at all (trailing or leading), nor anything else that attempts to convey soft "privacy". The reasons are hopefully communicated well. If they can be improved, PRs are most welcome! Just because a language provides functionality does not mean it is the best or most appropriate choice to achieve a goal, nor that using an alternative is "going around the language". You can do lots of things with |
…ng as “private properties”. Per airbnb#490 (comment)
…ng as “private properties”. Per airbnb/javascript#490 (comment)
* Updated Scss file structure * Added nvmrc file. Required node version is added, easier to use with nvm preinstalled. * Scss-lint task is added and now running on the fly * Resolved scss-lint issues in scss files, global scss-lint config edited * Support added for nesting selectors with parents (resolved issue with bem selectors, when writting scss code) * Added gitattributes file * Automated image optimization added * Added functionality, which checks if all dependencies are up to date. If not - gulp automatically installs them. * Added npmrc file (dependencies are automatically saved, even without defining flags, when installing and current version is defined in package.json) * eslintrc file is added * starter-template folder is removed * sass errors are not breaking gulp tasks * WebPack is running from gulp * Added gulp task cacheing for better task performance (faster repetitive tasks) * Added ability to make scss-lint errors silent
I didn't really understand all this fuss about truly private variables until I connected it with the concept of Hyrum's Law.
This is intuitive to me and makes clear sense. With that in mind and the scale of Airbnb it makes sense why this rule exists in their style guide and how 'fake private' is really just plain old 'public'. |
…ng as “private properties”. Per airbnb/javascript#490 (comment)
…ng as “private properties”. Per airbnb/javascript#490 (comment)
…ng as “private properties”. Per airbnb/javascript#490 (comment)
…ng as “private properties”. Per airbnb/javascript#490 (comment)
From the main section:
From the React section:
These two seem a bit inconsistent.
The text was updated successfully, but these errors were encountered: