You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Why are underscore prefixes for internal methods of a React component considered bad? #1024
They give people a false sense of "private"ness that could lead to bugs.
Reacted by Oleksii, Lyndsey Browning, Spike Brehm, Mitchell Porter, Andy Chen, Oleg Shalygin, David Cook, danilo neves cruz, Cherie Woo, Doug and 33 more
Reacted by Mauro Pineda, Omeid Matten, Jeremy Walker, Kieran, JohanG2012, Scot Matson, Anton Krichevskii, Carl Dunham, Derek Shang, Andrew P. and 35 more
Reacted by Hemant Sankhla, Howard, synonymouse, Novan, Borys Koretskyi, Denis Lepyohin, Micah, Nong (Ron) Wang, Daniel A. R. Werner, Mikhail S. and 5 more
Okay. Even though JavaScript doesn't support private variables, I still think the underscores help communicate the programmer's intent. If possible, @lencioni could you give an example of this false sense of "private"ness that lead to a bug? Or maybe a scenario where the underscores would confuse another programmer and lead them astray. I'm not disagreeing with you, I just want to have a better understanding of how this rule came about.
Reacted by Quentin Roy, Alexander Pushkov, 𖤬𝔫𝔡𝔶, Willian Fernandes, Dustin Wyatt, Eduardo Grajales Villanueva, Nicholas Kyriakides, Omeid Matten, Mauro Pineda, Jake Knerr and 65 more
Reacted by Michal Jarnot, lsabbagh, Lucas Castro and Jonathan Malatesta
Private means inaccessible. Your intent to privacy is irrelevant if the value is reachable, ie public.
For example, npm broke node once by removing an underscore-prefixed variable.
Reacted by Oleksii, Ben Crook, Nathan Broadbent, Andrzej Rehmann, David Ash, Bradley Farias, danilo neves cruz, Oleg Shalygin, Cherie Woo, Doug and 15 more
Reacted by Mauro Pineda, Omeid Matten, Marian Boda, Moshe Simantov, Jake Knerr, Jeremy Walker, Jair Elton Batista de Souza, Kieran, Andrew Albright, Sam McDavid and 51 more
Reacted by Ilya Gulkov, Jake Knerr, Mikhail Sidorov, Sergey, Robin Röper, Craig Morrison and Vladyslav Karasov
npm broke node once by removing an underscore-prefixed variable
If the variable wasn't prefixed they would have used it either way, and node would have still broke. When a meant-to-be-private variable is prefixed with an underscore there is at least one line of defence (a weak one, granted) preventing its use. Whereas when a meant-to-be-private variable isn't prefixed with an underscore, there is no line of defence (not even a weak one).
Reacted by David Livingston, TheWingMan, Quentin Roy, Peter Huang, Nathan Broadbent, Javier Bórquez, Victor, Alexander Pushkov, Alexei Malashkevich, Danny and 96 more
@ttmarek yes, but had they not prefixed it with an underscore, nobody would have been fooled into thinking it was actually private, and there would have been test coverage, and changing it would have prompted a semver-major version bump.
An underscore is in no way, whatsoever, a line of defense - it's just an incorrect assumption some developers make about a language that simply does not have the concept of privacy outside of closures.
Reacted by Gabriele Petronella, Bradley Farias, Cherie Woo, Doug, Brian Dayhoff, Stefano Cerelli, Fred Besteman, Łukasz Wojciechowski, Furkan Tunalı, Dave Welsh and 11 more
Reacted by Alexander Pushkov, Nicholas Kyriakides, Omeid Matten, Mauro Pineda, Marian Boda, Jeremy Walker, Jair Elton Batista de Souza, Sam McDavid, Scot Matson, Anton Krichevskii and 38 more
@ljharb So, in other words: underscore prefixed methods might confuse programmers from other languages into thinking that JavaScript supports private methods. Right?
That, or programmers who think that convention is the same as privacy.
Reacted by Ahmed Mahmoud, Adam Cahan, Oleg Shalygin, Christoffer Karlsson, Brian Dayhoff, Lucas Bernardo, Salman Zare, Furkan Tunalı, Stephen Coogan, Jonatan Santa Cruz and 9 more
Reacted by Collin Klopfenstein, testdev, Denis Lepyohin, Mike Chabot and Guillermo Zapata
Reacted by Omeid Matten, Oleg Shalygin, Anton Krichevskii, Greg and Denis Lepyohin
Okay, cool. Thanks @ljharb, I see what you're getting at. Do you think its worth adding a short blurb about this under the third bullet in react#methods?
Private stuff tends to change without warning, and without advertising as a breaking change.
The problem with that is that a lot of code could break without warning, because EVERYBODY ignores underscores:
Newbies don't know what it means. Experienced developers think they know what they're doing and the underscore doesn't apply to them.
Admit it. You've done that, too.
Reacted by nioni, David Mair Spiess, Tim Osborn, Thomas Marek, Ahmed Mahmoud, razh, Arvind Chembarpu, Adam Cahan, Levi Thomason, Hugeface and 48 more
Reacted by Rodrigo Ruiz, Alexander Pushkov, Nicholas Kyriakides, Omeid Matten, Mauro Pineda, Jimmy Breck-McKye, Jeremy Walker, agdespopoulos, Alfonso Nishikawa, Fırat Salgür and 14 more
Reacted by Morph, Mike Lyons, Edmond Chui, Jia Jing Loh, Dima Krutolianov and Fathima
Reacted by Jordan Harband, Thomas Marek, Ahmed Mahmoud, Levi Thomason, danilo neves cruz, Alan H, Greg, Matheus Santos, Romin Halltari, Bruno Capeleto and 2 more
They give people a false sense of "private"ness that could lead to bugs.
... but I'd like to elaborate on why.
In programming languages in general, the point of having a private property (as opposed to having all properties public) is so that you can trust a private variable not to be changed by outside code, unlike public properties which you need to assume can be changed by outside code at any time.
If you're absolutely hell bent on using inheritance in JavaScript, you don't have private properties. It is not a feature of inheritance in JavaScript. Everything is public. The logical thing to do is therefore to treat every property as a public property (because it is) - your code needs to assume that it can change at any time.
You can call a property _myProperty or __DONTFUCKINGCHANGEmyProperty but that doesn't make that property private. It's public. Private does not exist in the object composition model that you have chosen. You're trying to reap the benefits of a feature that you do not have. If you write your code in a way that assumes that your public-property-with-special-name-convetion does not change, you're just fooling yourself. The fucker can change at any moment, just like any other of your properties.
(Sidenote: This is React, and the following is not an option there, but in general, unless you need to create more than 50000 items per second, I personally think that you should consider using factory functions (https://www.youtube.com/watch?v=ImwrezYhw4w) instead of inheritance for creating objects. They have real privacy and do not have this problem)
Reacted by Sylvain MAUDUIT, Julian Mazzitelli, Joel Eisner, nioni, DexterHaslem, Augustin Le Fèvre, David Gatti, Tim Roberts, Thomas Marek, Joe Zoller and 89 more
Reacted by Alexander Pushkov, Omeid Matten, Alfonso Nishikawa, Joel Mussman, Denis Lepyohin, Nikolay Emrikh and Ales Kurecka
Reacted by grant, Kevin Suh, Dmitry Petukhov, Karl, Sean Yang and Eric Elliott
Reacted by Jordan Harband, Thomas Marek, Daniel Grant, Joel Eisner, Tim Osborn, Ahmed Mahmoud, Kris, grant, Luis Argumedo, Andrzej Rehmann and 20 more
Hi everyone, I've landed here after searching for an ESLint rule for enforcing this convention. Since I haven't found any, I've written one myself. In case anyone is interested, here it is: https://github.com/buildo/eslint-plugin-method-names
@ljharb You have a very peculiar definition of impact, but I agree that linting is intend to improve code, which effectively impacts it.
Again, running untrusted code does not erase "all bets" for secrecy and robustness - it only erases a large category of them. The only thing that makes "all bets off" is if untrusted code runs before your code, at which point, essentially nothing can be secured.
That is a pretty bold and risky proposition, and unless the same guide forces one to freeze builtins, useArray.$method and Object.$method instead of someArray.$method, someObj.$method et al, and a whole heap of other concerns, then the argument that using closure would provide you secrecy is pretty short sighted.
Even then if you take all the necessary precautions and measures, running untrusted code in the same context that you have secrets is foolishly naïve. It is that simple.
But then again, that is all irrelevant. I must iterate that Encapsulation and Visibility -- and by extension the use of underscore as convention to denote privacy -- is not a security concern, it is for separation of concern and differentiating implementation from the interface.
The interface contains every observable aspect of it. If _foo is observably present, it's part of the interface, no matter how much your documentation may try to insist otherwise.
Interfaces are protocol and contracts and like any other, they come with requirement and stipulations, if one opts to ignore the warning and recommendation of the API then they're on their own; if one does dumb things they end up in stupid situations.
Reacted by Robbie Speed, Andrew P. and Alfonso Nishikawa
Guys, I am sorry but I think this is obvious for everyone that this is not going anywhere and is useful for neither the participants nor the readers.
I was quite happy to see @ericelliott providing some data. I wish we could go in a path a bit more scientific like this. I am a bit sad it was not really followed on.
Without data (and I think you guys have a lot of this), this discussion is about opinions and ideas. I think we clearly reached the end of it and are currently locked inside a bad while(true) argue().
I respect opinions (in particular from experienced people). But I trust data. Properly analyzed, that produces knowledge.
Reacted by Jordan Harband, Omeid Matten, anton6, Mike Lyons and Giuliano Mega
hmm.. As I have understood it, this is basically a discussion about whether or not underscores should be allowed for method names. I kind of agree with the whole discussion about it not being private etc. I have however seen ALOT of React developers using underscore for states which are only UI states ex. the state "collapsed" in a menu component. This is something that I thought made sense and was doing myself until I started using this config and got a ton eslint errors. Up to this day, I still think this a good use of underscores and makes the code easier to reason about. But this is an aspect that not very many people seem to agree with or put a thought too over here.
"No private" is not an option for me, b/c it makes hard to reason about the class, and I'd like a rule that every public method should be documented. It forces you to think about your interface. I don't care about real data privateness, but I never understand sentences like "intractable people problem", b/c undesired underscores access easily can be spotted on a code review unlike variables without any mark.
Underscore as suffix works badly with my eyesight. I constantly miss them, and can't spot an error on a quick look over a codebase.
So I choose to use underscore prefixes for private methods. And just consider event handlers are part of public class API (b/c they called outside), so no underscores for them.
@ljharb Yeah, this is the core of this discussion. We have 2 groups of people here. For one, this will be change in the revision, because there is virtually no change in API. For the other, this will be a major change simply because it does not recognize this convention. Nevertheless, thank you for your opinion.
If you're stuck in the runtime that doesn't support private class field, and you want to prevent class consumer to access the private fields and methods, below are some workaround:
hide private methods with local functions
hide private fields with closure or local hashmap
Example for javascript runtime that doesn't support private field natively:
person.js:
letpersons=newMap()// "private method"functiongetAge(self){returnpersons.get(self).age}classPerson{constructor(name,age){// public fieldthis.name=name// "private field"persons.set(this,{ age })// private field}// public methodspeak(){// calling "private method"console.log('inside:',this.name,getAge(this))}}module.exports=Person
You'd want to use a WeakMap, not a Map, to avoid a memory leak, but yes, private class fields are a 100% safe and ideal approach for something you might otherwise stick an underscore on.
Activity
lencioni commentedon Aug 19, 2016
They give people a false sense of "private"ness that could lead to bugs.
ttmarek commentedon Aug 19, 2016
Okay. Even though JavaScript doesn't support private variables, I still think the underscores help communicate the programmer's intent. If possible, @lencioni could you give an example of this false sense of "private"ness that lead to a bug? Or maybe a scenario where the underscores would confuse another programmer and lead them astray. I'm not disagreeing with you, I just want to have a better understanding of how this rule came about.
ljharb commentedon Aug 19, 2016
Private means inaccessible. Your intent to privacy is irrelevant if the value is reachable, ie public.
For example, npm broke node once by removing an underscore-prefixed variable.
ttmarek commentedon Aug 19, 2016
If the variable wasn't prefixed they would have used it either way, and node would have still broke. When a meant-to-be-private variable is prefixed with an underscore there is at least one line of defence (a weak one, granted) preventing its use. Whereas when a meant-to-be-private variable isn't prefixed with an underscore, there is no line of defence (not even a weak one).
ljharb commentedon Aug 19, 2016
@ttmarek yes, but had they not prefixed it with an underscore, nobody would have been fooled into thinking it was actually private, and there would have been test coverage, and changing it would have prompted a semver-major version bump.
An underscore is in no way, whatsoever, a line of defense - it's just an incorrect assumption some developers make about a language that simply does not have the concept of privacy outside of closures.
ttmarek commentedon Aug 20, 2016
@ljharb So, in other words: underscore prefixed methods might confuse programmers from other languages into thinking that JavaScript supports private methods. Right?
ljharb commentedon Aug 20, 2016
That, or programmers who think that convention is the same as privacy.
ttmarek commentedon Aug 20, 2016
Okay, cool. Thanks @ljharb, I see what you're getting at. Do you think its worth adding a short blurb about this under the third bullet in react#methods?
lencioni commentedon Aug 20, 2016
I think so. I'd be happy to merge a PR that does that.
ljharb commentedon Aug 20, 2016
Sure, more helpful info is always good.
ericelliott commentedon Aug 26, 2016
My favorite reason:
Private stuff tends to change without warning, and without advertising as a breaking change.
The problem with that is that a lot of code could break without warning, because EVERYBODY ignores underscores:
Admit it. You've done that, too.
mpj commentedon Aug 26, 2016
I think @lencioni is perfectly correct by saying
... but I'd like to elaborate on why.
In programming languages in general, the point of having a private property (as opposed to having all properties public) is so that you can trust a private variable not to be changed by outside code, unlike public properties which you need to assume can be changed by outside code at any time.
If you're absolutely hell bent on using inheritance in JavaScript, you don't have private properties. It is not a feature of inheritance in JavaScript. Everything is public. The logical thing to do is therefore to treat every property as a public property (because it is) - your code needs to assume that it can change at any time.
You can call a property _myProperty or __DONTFUCKINGCHANGEmyProperty but that doesn't make that property private. It's public. Private does not exist in the object composition model that you have chosen. You're trying to reap the benefits of a feature that you do not have. If you write your code in a way that assumes that your public-property-with-special-name-convetion does not change, you're just fooling yourself. The fucker can change at any moment, just like any other of your properties.
(Sidenote: This is React, and the following is not an option there, but in general, unless you need to create more than 50000 items per second, I personally think that you should consider using factory functions (https://www.youtube.com/watch?v=ImwrezYhw4w) instead of inheritance for creating objects. They have real privacy and do not have this problem)
gabro commentedon Sep 5, 2016
Hi everyone, I've landed here after searching for an ESLint rule for enforcing this convention. Since I haven't found any, I've written one myself. In case anyone is interested, here it is: https://github.com/buildo/eslint-plugin-method-names
93 remaining items
omeid commentedon Jun 15, 2017
@ljharb You have a very peculiar definition of impact, but I agree that linting is intend to improve code, which effectively impacts it.
That is a pretty bold and risky proposition, and unless the same guide forces one to freeze builtins, use
Array.$methodandObject.$methodinstead ofsomeArray.$method,someObj.$methodet al, and a whole heap of other concerns, then the argument that using closure would provide you secrecy is pretty short sighted.Even then if you take all the necessary precautions and measures, running untrusted code in the same context that you have secrets is foolishly naïve. It is that simple.
But then again, that is all irrelevant. I must iterate that Encapsulation and Visibility -- and by extension the use of underscore as convention to denote privacy -- is not a security concern, it is for separation of concern and differentiating implementation from the interface.
Interfaces are protocol and contracts and like any other, they come with requirement and stipulations, if one opts to ignore the warning and recommendation of the API then they're on their own; if one does dumb things they end up in stupid situations.
QuentinRoy commentedon Jun 15, 2017
Guys, I am sorry but I think this is obvious for everyone that this is not going anywhere and is useful for neither the participants nor the readers.
I was quite happy to see @ericelliott providing some data. I wish we could go in a path a bit more scientific like this. I am a bit sad it was not really followed on.
Without data (and I think you guys have a lot of this), this discussion is about opinions and ideas. I think we clearly reached the end of it and are currently locked inside a bad
while(true) argue().I respect opinions (in particular from experienced people). But I trust data. Properly analyzed, that produces knowledge.
JohanG2012 commentedon Jun 24, 2017
hmm.. As I have understood it, this is basically a discussion about whether or not underscores should be allowed for method names. I kind of agree with the whole discussion about it not being private etc. I have however seen ALOT of React developers using underscore for states which are only UI states ex. the state "collapsed" in a menu component. This is something that I thought made sense and was doing myself until I started using this config and got a ton eslint errors. Up to this day, I still think this a good use of underscores and makes the code easier to reason about. But this is an aspect that not very many people seem to agree with or put a thought too over here.
Just wanted to add my 5 cents to the discussion.
kmmbvnr commentedon Feb 16, 2018
I experimented with all approaches.
ljharb commentedon Feb 16, 2018
Once class instance fields reach stage 4, you won’t have to compromise on it.
shelacek commentedon Jul 3, 2018
Once class instance fields reach stage 4, then I'll just find and replace my underscore prefixes ;-).
ljharb commentedon Jul 3, 2018
@shelacek and then that will be a semver-major/breaking change for each file in question. As long as you understand that, then go for it.
shelacek commentedon Jul 3, 2018
@ljharb Yeah, this is the core of this discussion. We have 2 groups of people here. For one, this will be change in the revision, because there is virtually no change in API. For the other, this will be a major change simply because it does not recognize this convention. Nevertheless, thank you for your opinion.
omeid commentedon Jul 4, 2018
ljharb commentedon Jul 4, 2018
omeid commentedon Jul 4, 2018
ljharb commentedon Jul 4, 2018
beenotung commentedon Sep 15, 2020
Private class field is now supported by some runtime.
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields
If you're stuck in the runtime that doesn't support private class field, and you want to prevent class consumer to access the private fields and methods, below are some workaround:
Example for javascript runtime that doesn't support private field natively:
person.js:
consumer.js:
console log:
ljharb commentedon Sep 15, 2020
You'd want to use a WeakMap, not a Map, to avoid a memory leak, but yes, private class fields are a 100% safe and ideal approach for something you might otherwise stick an underscore on.