Coding Style Guidelines

General rules

  • Maximal line length is limited to 80 characters.
  • If a statement has to be broken into two lines, second (and any subsequent) line should be indented by one level.
  • Indentation is always done using spaces, tabs are never used.
  • One level of indentation is 4 characters long.
  • Each file starts with a header containing the short license text.

Comments

Both C and C++ style comments are allowed.

  • C style comments (/* */) should be used for large block of comments, mostly at the beginning of the file.
  • The code itself should be commented by C++ line comments (//).
  • Code should be broken to small pieces (couple of lines each), every piece doing one simple task.
  • Each piece should be preceded by a comment explaining what is its intent.
  • Each code piece should be followed by a blank line.
  • C++ style line comment starts with two slashes followed by two spaces.
  • The text of comment begins with a capital letter and ends by a period.
//  Compute the factorial.
int factorial = 1;
for (int i = 2; i != 11; i++)
    factorial *= i;

//  Present the result to the user.
cout << "Factorial of 10 is " << factorial << "." << endl;

Identifiers

Identifiers are in lower case. If identifier consists of multiple words, the words are separated by underscores.

Identifiers should be meaningful rather than arbitrary. The only exception are control variables of short cycles where short names like i, it etc. can be used.

int sum = 0;
for (int i = 0; i != 100; i++)
     sum += i;

The type of the variable should not be explicitly marked in the identifier. I.e. no hungarian notation.

Function arguments should end by underscore. This way we can distinguish function arguments from member variables with the same name:

struct complex_t
{
    complex_t (float real_, float imaginary_) :
        real (real_),
        imaginary (imaginary_)
    {
    }

    float real;
    float imaginary;
};

Identifier for types (structs, classes, enums, typedefs) are postfixed by "_t" (e.g. complex_t).

Code blocks

For functions, structures, classes, enums and namespaces both opening bracket and closing bracket are placed on separate lines:

void fx ()
{
    //  Code goes here.
}

With for, while, if and else blocks opening bracket is on the same line as the control statement:

if (sum > 1000) {
    //  Code goes here.
}

Even if for, while, if or else block contains only a single statement, the statement should be placed on a separate line:

if (end)
    exit (1);

If the indenting of the controlled block incidentally collides with the control statement that's broken into two lines, second line of the control statement should be indented by 6 spaces rather than 4 to prevent confusion:

if (very_long_variable_name == 10000 &&
      another_horrendous_variable_name == 1000000 &&
      ludicrously_long_variable_name == 1000000000)
    counter++;

Operators

Unary operators are not separated from the expression in any way:

counter++;

Binary operators should be separated from adjacent expression by spaces:

z = x + y;

Subscripts and function calls are separated from the expression by space:

fx (my_array [0]);

String concatenation (PHP) should be separated by spaces:

$foo = $bar . " " . $bat;

Exceptions

  • Assertions say that the 0MQ developers do not expect this situation to ever happen, i.e. it is an internal error that demands a fix to the 0MQ code.
  • Errors say that the 0MQ developers expect this situation to happen in applications, i.e. it is an external error that suggests a fix to the application.
  • C++ exceptions are not to be used within the core codebase.

Public Interfaces

Public interfaces of components must not be called by code inside the interface.

For example, this is not allowed:

int f(int x) { return g (x); }
int fsucc(int x) { return f (x) + 1; }

Reserving public interfaces for the public is necessary for maintenance of public invariants, whilst allowing encapsulated implementation manipulators to work with weaker invariants temporarily. Even the mere existence of an otherwise correct call stands in the way of simple code changes, and particularly transparent invasions such as provided by external tracing and profiling tools. We don't want to confuse public calls to functions with internal calls, and we don't want to count inner calls when profiling.

The 0MQ system demands an invariant of socket I/O: no two threads may perform I/O at the same time. There are two ways this invariant can be maintained: by the client, or by 0MQ. In the latter case wrapping the code bodies of the function calls with a mutex lock suffices, however if one public API doing this called another there'd be an immediate deadlock.