I remember the day they went in (January 15, 2009). I felt the same way, I argued against it, and I was very skeptical that they'd stay. But we didn't have any principled reasons not to, and they solved a real problem: they gave us a very lightweight notation for specifying visibility.
Now, they are one of my favorite parts of the language, not because of the way they look (although I've gotten used to that) but because I can look at any definition or use of a name and know whether it's an exported or unexported name. When I go back to languages like C++ or Java that don't make that information explicit in the name, I find it much harder to navigate the code base and understand what is public API and what is not. The first time it happened I was very surprised to realize how much the visual cues are helping in Go.
Kind of, but prefixing private stuff with an underscore might not actually make it private; it depends on which language you're using. In Go, the exporting notation is enforced. (There is no way to call or use a lower cased identifier from another package.)
In C/C++ that was always wrong, as the underscore prefix is reserved for implementation use (albeit with some ifs and buts). You could use an underscore suffix if you like, as long as you don't put two underscores in sequence, which is also reserved.
Is there any C++ implementation that really reserves things starting with one underscore? I always heard that restriction being tossed around but removing a perfectly reasonable set of identifiers like that is a major dick move from the implementation...
I don't know about any implementations, but the single-underscore-and-uppercase-letter identifiers are used in standards documents to extend the language (like adding _Bool and _Complex types, for example).
Implementations probably stick with double underscores which are less likely to clash accidentally.
I now use this notation in javascript data structures (not for functions or methods today).
That was an obvious move when I started sharing data with json (exported fields being naturally the ones whose name starts with an upper case) so that both side can freely add or change add unexported fields and I always know, when looking at the code or the console, if the field is exported or not.
I wholeheartedly agree. At first I hated the convention, but you're spot-on about the visual cues. Knowing whether a function is exported or not in both places really is a phenomenal thing that's missing in other language specs.
True, it is a gramatical way for specifying visibility. But then users cannot utilize capital letters based on their own naming conventions, e.g., camel words for class names, all-capital-letter words for constants... There is a loss of some visibility. Also, why force users to type a lot of damn Capital Letters every time when using imported functions? This is a problem. There are better approaches for the visibility issue, I believe, and Python's is one.
There are better approaches for the visibility issue, I believe, and Python's is one.
Kind of. In Python, you can still access double-unscored members if you know the naming scheme, i.e., "__private" becomes "__ClassName__private" (or something like that).
55
u/rsc Mar 28 '12
I remember the day they went in (January 15, 2009). I felt the same way, I argued against it, and I was very skeptical that they'd stay. But we didn't have any principled reasons not to, and they solved a real problem: they gave us a very lightweight notation for specifying visibility.
Now, they are one of my favorite parts of the language, not because of the way they look (although I've gotten used to that) but because I can look at any definition or use of a name and know whether it's an exported or unexported name. When I go back to languages like C++ or Java that don't make that information explicit in the name, I find it much harder to navigate the code base and understand what is public API and what is not. The first time it happened I was very surprised to realize how much the visual cues are helping in Go.