Skip to content
Anton Kozhevnikov edited this page Sep 4, 2020 · 7 revisions

Coding style

  • Page width is approximately 120 characters. Screens are wide nowadays and 80 characters is an obsolete restriction.
  • Indentation: 4 spaces (no tabs). Exception: class access modifiers are indented with 2 spaces.
class A
{
  private:
    int n_;
  public:
    A();
};
  • Comments are inserted before the code with slash-star style starting with the lower case:
/* call a very important function */
do_something();
  • Spaces between operators:
if (i < 5) {
  j = 5;
} else {
  j = 1;
}

for (int k = 0; k < 3; k++) {
}

int lm = l * l + l + m;

double d = std::abs(e);

int k = idx[3];
  • Spaces between function arguments:
double d = some_func(a, b, c);

but not

double d=some_func(a,b,c);

and not

double d = some_func( a, b, c );
  • Spaces between template arguments, but not between <,> brackets:
std::vector<std::array<int, 2>> vec;

but not

std::vector< std::array< int, 2 > > vec;
  • Curly braces for classes and functions start form the new line:
class A
{
  ....
};

inline int num_points()
{
    return num_points_;
}
  • Curly braces for if-statements, for-loops, switch-case statements, etc. start at the end of the line:
for (int i: {0, 1, 2}) {
    some_func(i);
}

if (a == 0) {
    std::printf("a is zero");
} else {
    std::printf("a is not zero");
}

switch (i) {
    case 1: {
        do_something();
        break;
    }
    case 2: {
        do_something_else();
        break;
    }
}
  • Even single line 'if' statements and 'for' loops must have the curly braces:
if (i == 4) {
    some_variable = 5;
}

for (int k = 0; k < 10; k++) {
    do_something(k);
}
  • Reference and pointer symbols are part of type:
std::vector<double>& vec = make_vector();

double* ptr = &vec[0];

auto& atom = unit_cell().atom(ia);
  • Const modifier follows the type declaration:
std::vector<int> const& idx() const
{
    return idx_;
}
/* or */
auto const& atom = unit_cell().atom(ia);
  • Names of class members end with underscore:
class A
{
  private:
    int lmax_;
};
  • Setter method starts from set_, getter method is a variable name itself:
class A
{
  private:
    int lmax_;
  public:
    int lmax() const
    {
        return lmax_;
    }
    void set_lmax(int lmax__)
    {
        lmax_ = lmax__;
    }
};

However, the new style for setter methods is preferable:

class A
{
  private:
    int lmax_;
  public:
    /// Get lmax
    int lmax() const
    {
        return lmax_;
    }
    /// Set lmax
    int lmax(int lmax__)
    {
        lmax_ = lmax__;
        return lmax_;
    }
};
  • Order of class members: private, protected, public
class A
{
  private:
    int lmax_;
    void bar();
  protected:
    void foo();
  public:
    int lmax() const
    {
        return lmax_;
    }
};
  • Single-line functions should not be flattened:
struct A
{
    int lmax() const
    {
        return lmax_;
    }
};

but not

struct A
{
    int lmax() const { return lmax_; }
};
  • Header guards have a standard name: double underscore + file name in capital letters + double underscore
#ifndef __HEADER_HPP__
#define __HEADER_HPP__
...
#endif // __HEADER_HPP__
  • Variable names are all in lowercase and underscore-separated (aka 'snake_case'):
int num_bands;
std::complex<double> beta_psi;

but not

int NumBands;
/* or */
std::complex<double> BetaPsi;
/* or */
std::complex<double> Another_BetaPsi;

We use clang-format utility to enforce the basic formatting style. The .clang-format config file in the source root folder has the following definitions:

---
Language:        Cpp
Standard:        Cpp11
BreakBeforeBraces: 'Custom'
# Control of individual brace wrapping cases
BraceWrapping: {
    AfterClass: 'true'
    AfterControlStatement: 'false'
    AfterEnum : 'true'
    AfterFunction : 'true'
    AfterNamespace : 'false'
    AfterStruct : 'true'
    AfterUnion : 'true'
    BeforeCatch : 'false'
    BeforeElse : 'false'
    IndentBraces : 'false'
}
IndentCaseLabels: 'true'
AccessModifierOffset: -2
IndentWidth: 4
ColumnLimit: 120
UseTab: Never
AllowShortFunctionsOnASingleLine: 'None'
AllowShortIfStatementsOnASingleLine : 'false'
AllowShortLoopsOnASingleLine: 'false'
KeepEmptyLinesAtTheStartOfBlocks: 'true'
AlwaysBreakTemplateDeclarations: 'Yes'
PointerAlignment: Left
AllowAllParametersOfDeclarationOnNextLine: 'true'
AlignConsecutiveAssignments: 'true'
AlignConsecutiveDeclarations: 'false'
SortIncludes: 'false'
BinPackParameters: 'true'
BinPackArguments: 'true'
MaxEmptyLinesToKeep: 1
BreakConstructorInitializersBeforeComma: 'true'
#BreakConstructorInitializersStyle: 'BeforeComma'
ConstructorInitializerIndentWidth: 4
Cpp11BracedListStyle: 'true'

#AlwaysBreakAfterReturnType: None
AlwaysBreakAfterReturnType: 'TopLevelDefinitions'

...

The script 'clang_format.x' takes one argument (input source file) and produces a formatted output file with extra .fmt extension.

Class naming convention.

Problem: all 'standard' naming conventions are not satisfactory. For example, we have a class which does a DFT ground state. Following the common naming conventions it could be named like this:

  • DFTGroundState
  • DftGroundState
  • dft_ground_state

Last two are bad, because DFT (and not Dft or dft) is a well recognized abbreviation. First one is bad because capital G adds to DFT and we automatically read DFTG round state.

Solution: we can propose the following: DFTgroundState or DFT_ground_state. The first variant still doesn't look very good because one of the words is capitalized (State) and one (ground) - is not. So we pick the second variant: DFT_ground_state (by the way, this is close to the Bjarne Stroustrup's naming convention, where he uses first capital letter and underscores, for example class Io_obj).

Some other examples:

  • class Ground_state (composed of two words)
  • class FFT_interface (composed of an abbreviation and a word)
  • class Interface_XC (composed of a word and abbreviation)
  • class Spline (single word)

Exceptions are allowed if it makes sense. For example, low level utility classes like 'mdarray' (multi-dimensional array) or 'pstdout' (parallel standard output) are named with small letters.

Variable naming convention

Below is the list of standard names for some of the loop variables:

l - index of orbital quantum number
m - index of azimuthal quantum number
lm - combined index of (l,m) quantum numbers
ia - index of atom
ic - index of atom class
iat - index of atom typy
ir - index of r-point (real space point inside FFT grid or radial mesh)
ig - index of G-vector
idxlo - index of local orbital
idxrf - index of radial function
xi - combined index of lm and idxrf (product of angular and radial functions)
ik - index of k-point
itp - index of (theta, phi) spherical angles

The _loc suffix is often added to the variables to indicate that they represent the local fraction of the elements assigned to a given MPI rank.

Clone this wiki locally