24
$\begingroup$

In Go, capitalized identifiers are public (exported), while lowercase identifiers are private (within the package it's defined in). Most other programming languages don't have this sort of semantic difference of public/private by capitalization.

Cognate ignores non-capitalized tokens to allow for more natural language-looking code. Most programming languages don't have this due to their case-sensitivity for identifiers.

What are the pros and cons of semantically significant capitalization?

$\endgroup$
6
  • 11
    $\begingroup$ CON: NOT ALL COMPUTERS CAN GENERATE LOWERCASE LETTERS, WELL, NOT A PROBLEM WITH CURRENT COMPUTERS, BUT IN THE PAST THIS WAS THE CASE. $\endgroup$
    – Glen Yates
    Jul 13, 2023 at 20:39
  • 5
    $\begingroup$ @GlenYates Aʜ, ꜰᴀɪʀ ᴘᴏɪɴᴛ. Bᴜᴛ ꜱᴜʀᴇʟʏ ᴛʜᴇʏ ᴄᴏᴜʟᴅ ꜱᴛɪʟʟ ᴅᴏ ꜱᴍᴀʟʟ ᴄᴀᴘꜱ? $\endgroup$ Jul 14, 2023 at 1:53
  • 2
    $\begingroup$ Historically, I believe the significance of a leading capital was introduced by Smalltalk in the early 70s. As @GlenYates has so strikingly reminded us, this was roughly at the point where the industry started moving from 6-bit single-case character sets to ASCII and EBCDIC. $\endgroup$ Jul 14, 2023 at 7:14
  • 2
    $\begingroup$ One drawback is that when case is semantically significant in natural language, as occasionally it is in German and English, being forced to use a particular case for the sake of the programming language can be awkward. $\endgroup$
    – LarsH
    Jul 14, 2023 at 13:04
  • $\begingroup$ @GlenYates Ummm... what? $\endgroup$ Jul 15, 2023 at 6:22

8 Answers 8

39
$\begingroup$

Con: Doesn't work well for identifiers in alphabets other than latin

Most programing langues nowadays support unicode identifiers. This allows writing identifiers in languages other than english. However, capitalization does not exist in every language and may have other roles than in English.

Is מזהה public or private? You can't really tell. People writing code in such languages will be forced to prefix their identifiers with latin letters to get the desired behavior. Not an ideal situation.

Even in languages that have the concept of capitalization it may not be trivial to substitute a lower case word with one that starts with a upper case. For example in Greek different cases of constants have different meanings.

$\endgroup$
19
  • 3
    $\begingroup$ Technically, case sensitivity would work for Greek/Coptic, Cyrillic, Armenian, and a few other scripts. But yeah, you can't really capitalize a Hebrew letter or Chinese ideograph. $\endgroup$
    – dan04
    Jul 12, 2023 at 18:21
  • 14
    $\begingroup$ (for the curious, מזהה means "id") $\endgroup$
    – pxeger
    Jul 12, 2023 at 19:48
  • 1
    $\begingroup$ I'm never convinced there's a significant portion of programs written in non-English languages. Do you have stats? $\endgroup$
    – Passer By
    Jul 13, 2023 at 8:14
  • 1
    $\begingroup$ @PasserBy try searching for a relatively obscure problem, and many times after the first couple of pages of google results you usually start seeing chinese coding Q&A sites $\endgroup$
    – Pyritie
    Jul 13, 2023 at 9:32
  • 6
    $\begingroup$ @PasserBy I’ve seen quite a bit of code old code using Cyrillic (remember, the USSR was isolated technologically during the early years of electronic computers), and a nontrivial amount of modern code that uses CJK unified ideographs mixed with Latin characters (this is rather common for isolated projects coming out of China). And then there’s always the cases of ALGOL 68, Citrine, Internaitional Scheme, Scratch, or FOCAL (all localized to varying degrees to numerous languages). $\endgroup$ Jul 13, 2023 at 12:08
27
$\begingroup$

Con: inflexibility

Using Go as an example, if you have a private identifier and want to make it public, you have to effectively rename it, which means changing code at every point where the identifier is used, as opposed to just changing the declaration. And since there are only two letter cases, it prevents the language from adding another option, such as some kind of partially exported identifiers.

As another example, if a language uses capitalization to distinguish between types and variables, it's going to cause problems if you later want to add the ability to use types as values (“first-class types”):

$\endgroup$
2
  • 3
    $\begingroup$ In my personal experience (we use a prefix for non-public members in C# which we're supposed to remove if we make it public), your first point is rarely a problem: Since a public method is part of the API, it has different requirements (regarding parameter validation etc.) than a private method. So, often, you need to change other aspects of the method as well when making it public or just "wrap" it with a new public method. If the method can really be made public as it is, the IDE makes renaming it everywhere easy, since it had limited scope so far. $\endgroup$
    – Heinzi
    Jul 13, 2023 at 14:12
  • 1
    $\begingroup$ Javascript's #private fields are another example where you have to rename things to change their visibility. $\endgroup$
    – kaya3
    Jul 24, 2023 at 13:00
18
$\begingroup$

Cons:

You move representation of a binary property into the identifier concept. Go is actually a good example of why this is a bad idea. With their decision, they are now stuck with a binary visibility concept. Most language have either nothing ore a lot more granularity than that. The Go way, you can't share definitions between an API and an implementation package.

For most languages, there is syntax highlighting which allows you to colorize the visibility definition and ignore it, if you don't care.

The highlevel point against is that such decisions are usually made at a stage where the language is still very simple and the decision looks reasonable. However, languages get more complex if they are successful. But such fundamental decisions cannot be undone in a compatible way. Adding another keyword or braces where they weren't allowed before is a mostly or completely compatible change.

$\endgroup$
6
  • $\begingroup$ What do you mean by "you can't share definitions between an API and an implementation package"? What isn't shared? Why do you have two packages? What hypothetically solves your problem? $\endgroup$
    – Passer By
    Jul 13, 2023 at 8:26
  • $\begingroup$ If a struct in your API has a field, that field is either public or your implementation is in the API package. Having API and implementation in the same package is uncommon in all languages and doesn't play well with code generators often used in Go. A solution is to restrict visibility to a group of packages like private[package] in Scala. Java modules also provide a solution that is more complex as they had to add it at a later point. $\endgroup$
    – feldentm
    Jul 13, 2023 at 9:21
  • 1
    $\begingroup$ I have no experience in Go code generators, but having the API and implementation in the same package is pretty much intended isn't it? $\endgroup$
    – Passer By
    Jul 13, 2023 at 9:35
  • $\begingroup$ "For most languages, there is syntax highlighting which allows you to colorize the visibility definition and ignore it, if you don't care." I have seen color highlights, but never what you are describing. What language and editor combo has this? $\endgroup$
    – James
    Jul 13, 2023 at 18:13
  • $\begingroup$ @James most languages use ordinary keywords for this purpose and all IDEs I've seen in the last two decades had special colors for at least the entire keyword group. Am I missing something here? $\endgroup$
    – feldentm
    Jul 13, 2023 at 19:46
13
$\begingroup$

Case has long been used by convention to indicate roles of identifiers. For instance, in C it's conventional to use ALLUPPER for macros, and either snake_case or camelCase for other identifiers. In many languages, classes are conventionally named with an initial uppercase letter; this usually goes along with camelCase for the rest of the name.

Making this semantically significant simply formalizes these common programming styles. It's analogous to the way languages like Python make indentation significant to the parser, rather than it just being used to make the code easier for humans to read.

So the main "pro" is that programs in the language are forced to follow a consistent style, making it easier for everyone to read each other's programs.

This can also make it easier for programming tools to provide assistance.

The con, as other answers say, is that it doesn't work well when programming in (human) languages that don't have upper/lowercase similar to Latin alphabets.

$\endgroup$
4
  • $\begingroup$ In C, macros are not always capitalized. For instance bool is a macro expanding to _Bool, dating back to C99. There is often a getc macro in <stdio.h> implementations. Lower cased macros are used for shortening nested member access in structures: #define s6_addr in6_u.u6_addr8. It would be bad for macros to be restricted to upper case or even a leading upper case character. $\endgroup$
    – Kaz
    Jul 14, 2023 at 22:58
  • $\begingroup$ @Kaz getc() is specified as a function, but built-in functions are allowed to be implemented as macros. I think bool is an exception because it was originally an implementation extension keyword, and when it became a standard macro they kept the lowercase name for compatibility. $\endgroup$
    – Barmar
    Jul 14, 2023 at 23:57
  • $\begingroup$ In ISO C there are other examples of lower case macros. The errno symbol from <errno.h> is explicitly defined a macro in ISO C which "expands to a modifiable lvalue". The behavior is undefined if a program uses #undef on it to access an errno object. In <stdio.h>, stdin, stdout and stderr are also defined as macros. (And have were that way in ancient Unix; something along the lines of #define stdin __filetab[0] or whatever.) In <assert.h>, assert is a macro. $\endgroup$
    – Kaz
    Jul 15, 2023 at 0:17
  • $\begingroup$ @Kaz The common denominator is that these things are used as if they're variables or functions, but they've been implemented as macros for various reasons (e.g. errno because of multi-threading). $\endgroup$
    – Barmar
    Jul 15, 2023 at 0:23
7
$\begingroup$

One advantage is that you can lexically distinguish between two different classes of identifier, which could be useful if they need to be parsed differently.

A good example of this is Haskell, which uses capitalized identifiers to denote types, and non-capitalized for functions. This avoids the need for its parser to determine based on the context which kind of identifier it is looking at, and results in a simpler, more efficient parser.

$\endgroup$
2
  • 1
    $\begingroup$ I think your remark about Haskell is wrong. In value contexts, it uses lowercase for variables and uppercase for constructors; in type contexts, it uses lowercase for type variables and uppercase for types. $\endgroup$
    – xigoi
    Jul 14, 2023 at 22:34
  • $\begingroup$ @xigoi - probably; it's been a while since I last used Haskell, so could easily have misremembered the details. I think my point still remains valid, though. $\endgroup$
    – occipita
    Jul 15, 2023 at 12:45
6
$\begingroup$

Con: screenreaders typically either don’t announce all-caps any differently to lowercase words, or, worse, can read them letter by letter as if they were an abbreviation.

Language developers shouldn’t bake in inaccessible practices into the base system.

$\endgroup$
4
  • $\begingroup$ This is an issue with screen readers (which are generally not designed to read code), not the with code itself. $\endgroup$
    – Trang Oul
    Jul 14, 2023 at 8:30
  • $\begingroup$ Well, that boils down to a philosophical code-is-for-computers can code-is-for-users. Personally I always go for the second option. $\endgroup$ Jul 14, 2023 at 11:04
  • 1
    $\begingroup$ I somehow agree, but does any screen reader read the code correctly (as e.g. "tab string my string equals quote foo quote semicolon new line")? $\endgroup$
    – Trang Oul
    Jul 14, 2023 at 13:43
  • $\begingroup$ Anyone using a screen reader for working with code in detail is likely to need to find one that is able to distinguish between cases anyway, as most languages are case significant. Most visually-impaired programmers I've talked to use a program called NVDA, which seems to support this $\endgroup$
    – occipita
    Jul 15, 2023 at 13:14
5
$\begingroup$

Similar to occipita's answer, but for humans instead of compilers:

When reading code, it can be useful to immediately be able to tell whether a given identifier is public or private, without going to find its definition (using the example of Go). This will make it easier to pick out identifiers that definitely came from the current file, and which might have come from elsewhere. It might also allow you to make quicker and better decisions on whether you can safely change a function: if it's capitalised, then it's likely to be used somewhere else in the codebase, so changing it might be riskier.

$\endgroup$
2
  • $\begingroup$ Because the behavior of private functions is never exposed through the public API? This is complete nonsense. It does not matter if a bug is introduced from code that can be called directly or not. $\endgroup$
    – feldentm
    Jul 13, 2023 at 7:05
  • $\begingroup$ @feldentm Ok maybe not the behaviour necessarily, but the type signature for example. Surely you can see what I mean even if the example isn't totally applicable $\endgroup$
    – pxeger
    Jul 13, 2023 at 11:37
5
$\begingroup$

Cons: not extensible

There are only two cases. It can be a hard time if, for example, we need to add protected support to a newer version of the language.

Cons: dynamic keys

For example, in JavaScript, objects are often used as maps, and class properties can be dynamic too. A static analyser cannot tell if obj.x is accessing a private property, or reading the value corresponding to a user input x.

Cons: special words

Some words are written in specific cases. For example, forcing iOS to be ios or IOS at language level can be a bit ugly.

$\endgroup$
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .