The D Style
The D Style is a set of style conventions for writing D programs. The D Style is not enforced by the compiler. It is purely cosmetic and a matter of choice. Adhering to the D Style, however, will make it easier for others to work with your code and easier for you to work with others' code. The D Style can form the starting point for a project style guide customized for your project team.
Submissions to Phobos and other official D source code will follow these guidelines.
Whitespace
- One statement per line.
- Use spaces instead of hardware tabs.
- Each indentation level will be four columns.
Comments
- Use // comments to document a single line:
statement; // comment statement; // comment
- Use block comments to document a multiple line block of
statements:
/* comment * comment */ statement; statement;
- Use version (none) to ‘comment out’ a piece of trial code
that is syntactically valid:
version (none) { /* comment * comment */ statement; statement; }
It can be turned on with version(all):version (all) { /* comment * comment */ statement; statement; }
- Use nesting comments to ‘comment out’ a piece of syntactically invalid code:
/+++++ /* comment * comment */ { statement; statement; +++++/
Naming Conventions
- General
- Unless listed otherwise below, names should be camelCased (this
includes all variables). So, names formed by joining multiple
words have each word other than the first word capitalized. Also, names
do not begin with an underscore ‘_’ unless they are
private.
int myFunc(); string myLocalVar;
- Modules
- Module and package names should be all lowercase, and only contain
the characters [a..z][0..9][_]. This avoids problems when dealing with
case-insensitive file systems.
import std.algorithm;
- Classes, Structs, Unions, Enums, Templates
- The names of user-defined types should be PascalCased, which is the
same as camelCased except that the first letter is uppercase.
class Foo; struct FooAndBar;
- An exception is that eponymous templates that return a value instead of
a type should not be capitalized, as they are conceptually more similar
to functions.
template GetSomeType(T) { alias T GetSomeType; } template isSomeType(T) { enum isSomeType = is(T == SomeType); }
- Functions
- Function names should be camelCased, so their first letter is lowercase.
This includes properties and member functions.
int done(); int doneProcessing();
- Constants
- The names of constants should be camelCased just like normal variables.
enum secondsPerMinute = 60; immutable hexDigits = "0123456789ABCDEF";
- Enum members
- The members of enums should be camelCased, so their first letter is
lowercase.
enum Direction { bwd, fwd, both } enum OpenRight { no, yes }
- Keywords
- If a name would conflict with a keyword, and it is desirable to use the
keyword rather than pick a different name, a single underscore
‘_’ should be appended to it. Names should not be
capitalized differently in order to avoid conflicting with keywords.
enum Attribute { nothrow_, pure_, safe }
- Acronyms
- When acronyms are used in symbol names, all letters in the acronym
should have the same case. So, if the first letter in the acronym
is lowercase, then all of the letters in the acronym are lowercase, and
if the first letter in the acronym is uppercase, then all of the
letters in the acronym are uppercase.
class UTFException; ubyte asciiChar;
Meaningless Type Aliases
Things like:
alias void VOID;
alias int INT;
alias int* pint;
should be avoided.
Declaration Style
Since the declarations are left-associative, left justify them:
int[] x, y; // makes it clear that x and y are the same type
int** p, q; // makes it clear that p and q are the same type
to emphasize their relationship. Do not use the C style:
int []x, y; // confusing since y is also an int[]
int **p, q; // confusing since q is also an int**
Operator Overloading
Operator overloading is a powerful tool to extend the basic types supported by the language. But being powerful, it has great potential for creating obfuscated code. In particular, the existing D operators have conventional meanings, such as ‘+’ means ‘add’ and ‘<<’ means ‘shift left’. Overloading operator ‘+’ with a meaning different from ‘add’ is arbitrarily confusing and should be avoided.
Hungarian Notation
Using hungarian notation to denote the type of a variable is a bad idea. However, using notation to denote the purpose of a variable (that cannot be expressed by its type) is often a good practice.
Properties
Functions should be property functions whenever appropriate. In particular, getters and setters should generally be avoided in favor of property functions. And in general, whereas functions should be verbs, properties should be nouns, just like if they were member variables. Getter properties should not alter state.
Documentation
All public declarations will be documented in Ddoc format.
Unit Tests
As much as practical, all functions will be exercised by unit tests using unittest blocks immediately following the function to be tested. Every path of code should be executed at least once, verified by the code coverage analyzer.
Additional Requirements for Phobos
In general, this guide does not try to recommend or require that code conform to any particular formatting guidelines. The small section on whitespace at the top contains its only formatting guidelines. However, for Phobos and other official D source code, there are two additional requirements:
- Braces should be on their own line. There are a few exceptions to this (such as when declaring lambda functions), but with any normal function block or type definition, the braces should be on their own line.
void func(int param)
{
if(param < 0)
{
...
}
else
{
...
}
}
We are not necessarily recommending that all code follow these two rules. They're both likely to be controversial in any discussion on coding standards. However, they are required in submissions to Phobos and other official D source code.