7
$\begingroup$

In many languages, there is a well-agreed upon variable/class/type casing convention (often camelCase or snake_case for variables, PascalCase for classes and types.) In most languages I have dealt with, these casings are optional and up to changing for personal preference, but are incorporated into the standard library. However, I know that some languages do enforce that the user follow a certain name casing convention. What are some reasons why a language should or should not enforce a casing convention?

Obviously you can’t enforce camelCase vs camelcase, but you can prevent CamelCase from passing. Other casing conventions (i.e. ALL_CAPS) may be easier to enforce.

$\endgroup$
3
  • 1
    $\begingroup$ How can the casing convention even be enforced? If I declare a variable named camelcase, how should the compiler know that's two words instead of one, and therefore that it should be camelCase instead? If I name a class IP, how should the compiler know it's an acronym and not a mis-cased spelling of Ip? $\endgroup$
    – kaya3
    Commented May 22, 2023 at 17:38
  • 2
    $\begingroup$ @kaya3 It could check if a class starts with a capital letter, or if a variable starts with one. It could also enforce something like ALL_CAPS $\endgroup$
    – Jacob
    Commented May 22, 2023 at 18:30
  • 2
    $\begingroup$ @kaya3 You can't enforce camelcase vs. camelCase sure, but you can enforce camelCase vs. camel_case easily. $\endgroup$ Commented May 22, 2023 at 19:20

7 Answers 7

8
$\begingroup$

There are some languages where there is semantic meaning in whether a name begins with an uppercase or lowercase letter:

  • In Prolog, a name beginning with uppercase is a variable, while a name beginning with lowercase is an atom.
  • In ANTLR, a name beginning with uppercase is a lexer rule, while a name beginning with lowercase is a parser rule.
  • In React, HTML elements are written in lowercase while components start with an uppercase letter.
  • In Haskell and OCaml, constructor names start with uppercase letters while variable names start with lowercase letters, so that these can be distinguished when they occur in patterns.

This makes sense in languages where all names belong to one of two categories, particularly if the parser needs to know which is which (i.e. before name resolution occurs). It would be possible to use other symbols to distinguish names, e.g. $x for variables, but this tends to make the syntax "noisier", and can mean fewer symbols are available for other purposes.

These aren't examples of the compiler "enforcing" a stylistic convention, rather it's the compiler attaching meaning to the casing so that it's no longer just stylistic. But the consequence is similar ─ names for certain things must be written in certain ways.

$\endgroup$
1
  • 2
    $\begingroup$ React is another example, custom components must start with a capital letter to distinguish them from HTML elements $\endgroup$
    – mousetail
    Commented May 22, 2023 at 20:52
7
$\begingroup$

Pro: Lighter syntax

Haskell requires that all type names start with a capital letter. This means that in a context where types are expected (like the signature of a function), lowercase names can refer to type variables. That is, the type of the identity function id x = x is not, say, id :: A => A -> A, but just id :: a -> a. The fact that a lowercase name appears where a type should be is enough to know that it is a variable, because it cannot be a legal type name.

$\endgroup$
2
  • 3
    $\begingroup$ Note that this is problematic when using Unicode, as many scripts don't have a capital/lower case distinction. $\endgroup$
    – prosfilaes
    Commented May 22, 2023 at 21:56
  • $\begingroup$ This is also useful when pattern matching: you know Foo refers to some constructor and foo is only a variable $\endgroup$
    – user
    Commented May 22, 2023 at 22:03
5
$\begingroup$

Pro: Makes it possible to do static parsing

APL has an extremely lightweight syntax without decoration/noise (depending on your perspective). E.g. you can apply a function to an argument, simply by justaposing function and argument or even placing the function between two arguments. You can also create an array of values, simply by juxtaposing them. Higher-order functions (think map, reduce, etc.) apply to a function, simply by being adjacent to it. Finally, adjacent functions combine according to a set of combinator rules, thereby deriving a new function. All this makes it completely impossible to parse an APL expression before run time, as only then will you know the syntactic class of each identifier.

As an example, take a b c d which could be a single array of values [a,b,c,d], or b c d could be an array, and a function applied to it a([b,c,d]) or b could be an infix operator taking a on its left and [c,d] on its right. Or maybe c is actually a a high-order function that takes the function b and applies it to a and d… All-in-all, there are 67 legal ways to parse a b c d:

 Number of adjacent identifiers: 1 2 3 4 5 6 7 8 9
 Number of ways to parse:   3 7 20 67 234 814 2841 9910 34593… you get the idea!

Now, a very simple casing conversion can resolve all this. For example, I recommend lowercase arrays, uppercase functions, and using underscores to mark the sides of higher-order functions that bind parameters (the underscores being the "glue"). With this, the [a,b,c,d] remains a b c d while a([b,c,d]) is A b c d and a B c d has B be that infix function that takes [c,d] as right argument. And a B _C d is _C taking B and creating a new function that is applied between a and d. With such a scheme, every expression can only mean one thing.

Pro: Lightweight change of syntactic class

BQN is an APL derivative that takes this idea step further. Not only does it enforce correct casing of initials, if you change the case of a name, it changes the syntactic class of its value. This allows fully functional programming in the array paradigm: By restating a function's name with a lowercase initial, it becomes an array which can be combined with other arrays in a structure. And by restating an array variable's name with an uppercase initial, it becomes a constant function.

$\endgroup$
1
  • $\begingroup$ In most other languages, this is like saying differentiating identifiers and operators by using words and symbols is already a casing-like convention. So the bad part already existed. The keyword related questions are part of the consequences. Good point. But whether it is a pro or con may depend on what solutions to the keyword related questions the language has used. $\endgroup$
    – user23013
    Commented Jul 16, 2023 at 8:45
3
$\begingroup$

The C grammar has an ambiguity in it. It resolves this by distinguishing between two tokens: IDENTIFIER and TYPE_NAME. When a typedef is found, the compiler feeds this information back to the lexical analyser, so that any subsequent appearance of this identifier can be returned as a TYPE_NAME rather than an IDENTIFIER.

What this means in practice is that C must be parsed from top to bottom. You must declare a type before it is used as a type.

There are essentially three ways around this:

  • Keep types and variable names syntactically distinct, that is, design your syntax in such a way that a type name and a variable name can never be confused because they never appear in the same place. This is an advantage of Pascal-style declaration syntax.
  • Keep types and variable names lexically distinct. Haskell has a similar issue that requires making type names and type variables distinct, and it solves this problem by mandating that type names begin with a capital letter. ML solves the same problem by requiring that type variables start with an apostrophe. Prolog's variable vs atom syntax is similar.
  • Live with the ambiguity and resolve it in a later pass.

There are situations in C++ where this third option is mandated. There is a rule in the standard which says that if something looks like a declaration, then it is, otherwise if it looks like a statement, then it is, otherwise it's a syntax error.

The point here is that enforcing "casing convention" sometimes makes your language, as a whole, easier to use.

I've been talking about types and variables, but many languages have more than one category that an identifier could be in, and a language could mix and match approaches if that seems appropriate.

C has four categories: identifiers (i.e. functions and variables), type names, field names (i.e. members of structs or unions), and labels (i.e. goto targets). The first three require forward declarations, but labels are distinguished syntactically.

$\endgroup$
3
$\begingroup$

Pro: Better defaults

Scala has a convention of calling constants with names that start with an uppercase letter.

While

f() match
  case 4 => println("four")
  case q => println(q)

binds the name q to the result of the function when it doesn't match the patterns above,

f() match
  case Pi => println("pi")

compares the result to the constant Pi and only matches if it is equal. There are ways to get the alternate behavior (backticks), but enforcing that constants have some different naming than variables means there are some places where different behaviors can occur basing on the name.

$\endgroup$
3
$\begingroup$

Con: Less flexibility in naming

Sometimes, you want an identifier to refer to a thing that exists out in the world, and its exact spelling, including capitalisation is important. Forcing a certain use of casing can lower readability or even mix up names that differ only by capitalisation. E.g. you might want a variable called iPads that contains information about certain tablet devices. Now, if the naming convention forces you to call the variable IPads, a reader might think it has to do with advertising based on intellectual property, or maybe to do with internet protocol addresses.

$\endgroup$
3
  • $\begingroup$ why multiple answer posts here? $\endgroup$
    – starball
    Commented May 23, 2023 at 16:34
  • 1
    $\begingroup$ @starball They are not related. $\endgroup$
    – Adám
    Commented May 23, 2023 at 16:54
  • $\begingroup$ note: related meta discussion: Policy on multiple answers by the same user $\endgroup$
    – starball
    Commented May 23, 2023 at 16:56
2
$\begingroup$

To design for a collaborative ecosystem with cohesive user experience

How much do you anticipate or want for people to share code libraries with each other? When there's sharing, inconsistencies can make for a poorer user experience. That can be part of why you'd want to make your language more opinionated with respect to naming conventions (though typically even when languages go harder on this, they still give users an escape hatch to go against the language's opinions).

Casing is often used as a tool to communicate something about what something is. For example, in C/C++, there are conventions to use SCREAMING_SNAKE_CASE for macros. That kind of advertising of what something is in the name itself can be useful.

Note: Technically, if you plan on having tooling that assists in readability, there can be other ways of achieving that same communication. For example, syntax highlighting in code editors, or symbol-type icons in autocomplete menus. Just don't forget that one of the great strengths of having a language where the source is just written with text is that people can read and write in the language if they have any tool that can display and edit text- fancy dedicated tooling or not (which- historically speaking- probably contributed at least in part to those casing conventions' establishment).

If you turn it the other way around and use casing for semantics

I suppose you could design a language where the compiler uses casing information as a conveyor of semantics (Ex. imagine if C/C++ had no #define, and a top-level SCREAMING_SNAKE_CASE that isn't a language-keyword means to the compiler/preprocessor that what follows should be a macro body instead of just being a signal to human readers)

But at that point it's less about enforcement of the casing and more about enforcing that the language usage as a whole is well-formed.

$\endgroup$

You must log in to answer this question.

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