- Problem
- Background
- Proposal
- Details
- Open questions
- Rationale based on Carbon's goals
- Alternatives considered
The goal of this proposal is to establish naming conventions for:
- Idiomatic Carbon code.
- Carbon-provided features, including:
- Keywords, such as
fn
orfor
. - Type literals, such as
i32
. - Types, such as
bool
orString
.
- Keywords, such as
The reason for resolving this through proposal is to ensure we're headed in a reasonably consistent path as we write early documentation and example code.
Naming conventions are an issue frequently addressed by style guides. A few examples of language-provided guidelines are:
- Effective Go
- Python's PEP 8
- Note PEP 8 offers a list of naming styles.
- Rust API Guidelines
- Swift's API Design Guidelines
Related issues:
- Issue #543: pick names for fixed-size integer types covers numeric type literal naming.
- Issue #750: Naming conventions for Carbon-provided features was used for initial naming convention discussion.
Related proposals:
- Proposal #720: Property naming in C++ covers nuances of property naming.
Only UpperCamelCase
and lower_snake_case
conventions will be used, in order
to minimize the variation in rules.
- For idiomatic Carbon code:
UpperCamelCase
will be used when the named entity cannot have a dynamically varying value. For example, functions, namespaces, or compile-time constant values.lower_snake_case
will be used when the named entity's value won't be known until runtime, such as for variables.
- For Carbon-provided features:
- Keywords and type literals will use
lower_snake_case
. - Other code will use the guidelines for idiomatic Carbon code.
- Keywords and type literals will use
In other words:
Item | Convention | Explanation |
---|---|---|
Packages | UpperCamelCase |
Used for compile-time lookup. |
Types | UpperCamelCase |
Resolved at compile-time. |
Functions | UpperCamelCase |
Resolved at compile-time. |
Methods | UpperCamelCase |
Methods, including virtual methods, are equivalent to functions. |
Generic parameters | UpperCamelCase |
May vary based on inputs, but are ultimately resolved at compile-time. |
Compile-time constants | UpperCamelCase |
Resolved at compile-time. See constants for more remarks. |
Variables | lower_snake_case |
May be reassigned and thus require runtime information. |
Member variables | lower_snake_case |
Behave like variables. |
Keywords | lower_snake_case |
Special, and developers can be expected to be comfortable with this casing cross-language. |
Type literals | lower_snake_case |
Equivalent to keywords. |
Boolean type and literals | lower_snake_case |
Equivalent to keywords. |
Other Carbon types | UpperCamelCase |
Behave like normal types. |
Self and Base |
UpperCamelCase |
These are similar to type members on a class. |
Supposing let
might be used to designate a constant, consider the following
code:
package Example;
let CompileTimeConstant: i32 = 7;
fn RuntimeFunction(runtime_constant: i32);
In this example, CompileTimeConstant
has a singular value (7
) which is known
at compile-time. As such, it uses UpperCamelCase
.
On the other hand, runtime_constant
may be constant within the function body,
but it is assigned at runtime when RuntimeFunction
is called. Its value is
only known in a given runtime invocation of RuntimeFunction
. As such, it uses
lower_snake_case
.
Carbon-provided items are split into a few categories:
- Keywords; for example,
for
,fn
, andvar
- Type literals; for example,
i<digits>
,u<digits>
, andf<digits>
- Boolean type and literals; for example,
bool
,true
, andfalse
- The separate categorization of booleans should not be taken as a rule that only booleans would use lowercase; it's just the only example right now.
Self
andBase
- Other Carbon types; for example,
Int
,UInt
, andString
Note that while other Carbon types currently use UpperCamelCase
, that should
not be inferred to mean that future Carbon types will do the same. The leads
will make decisions on future naming.
- Code that is easy to read, understand, and write
- The intent is that limiting to
UpperCamelCase
andlower_snake_case
will offer developers a limited number of style rules to learn. - There is a desire to maintain good ergonomics for developers.
- The intent is that limiting to
- Interoperability with and migration from existing C++ code
- There is a general desire to maintain naming consistency with C++, and
this can be seen with keywords such as
for
as well as booleans.
- There is a general desire to maintain naming consistency with C++, and
this can be seen with keywords such as
A couple naming conventions that were discussed briefly are:
lowerCamelCase
names came up, but are hard to distinguish fromlower_snake_case
for single-word identifiers. By contrast,UpperCamelCase
andlower_snake_case
are distinct, whether a single word or multiple.ALL_CAPS_SNAKE_CASE
is used in C++ code, such as for macros and compile-time constants. With Carbon, we hope the language is simple enough that the readability benefit of an additional naming convention wouldn't outweigh the cost of giving developers more naming conventions to learn.
In detail, individual naming decisions that had alternative patterns or options discussed were:
- Type literals use
lower_snake_case
as described in issue #543: pick names for fixed-size integer types.i8
is more ergonomic thanInt8
for brevity.i32
andi64
maintain the same length as C++'sint
.- We don't want to use
I32
becauseI32
can be hard to visually distinguish with132
orl32
, even though it may help screen readers.
- Booleans use
bool
,true
, andfalse
mainly because there's a desire not to skew from C++.- While leads are okay with some things being shadowed, such as
Self
andBase
, there is a desire not to allow shadowing of booleans.
- While leads are okay with some things being shadowed, such as
Self
andBase
areUpperCamelCase
because leads want them to look more like normal types.- They may be implemented as a hybrid approach, using something similar to lookup in classes so they aren't quite keywords, but somewhat similar to keywords because leads may want to reject them as identifiers in non-class contexts.
String
and potentially other names follow idiomatic naming conventions.- Note that, in this case, divergence from C++ is accepted.
Taking that into consideration, and that we are likely to keep
lower_snake_case
for keywords and type literals in particular, a couple
options discussed would have mainly affect self
, base
, and string
:
- Anything language-provided without needing an
import
is alwayslower_snake_case
.i32
,bool
,true
,self
,base
,string.is_empty()
- As above, but prelude class members follow standard naming conventions.
i32
,bool
,true
,self
,base
,string.IsEmpty()
The understanding is that the difference between bool
being treated similarly
to a keyword and Self
being treated similarly to a type (both regardless of
implementation) is somewhat arbitrary. The decision not to use
lower_snake_case
consistently depends mainly on the leaning of the leads, that
self
and base
felt like they shouldn't strictly be treated as keywords, and
string
felt like the point where users should expect something more like an
idiomatic class. Future borderline cases may need to be decided by leads whether
they should be treated as more keyword-like or type-like.