Maria Coding Style

Marko Mäkelä

Maria, or the Modular Reachability Analyzer, consists of over 50,000 lines of C++ code. Since all of the code has gone through the hands of a single person who has tried to maintain some conventions, the code follows certain principles. This article is the first attempt at documenting and justifying these principles.

The coding style is largely based on the conventions documented by Ellemtel Telecommunication Systems Laboratories in Programming in C++, Rules and Recommendations, on the way the c++-mode of GNU Emacs works with its default settings, and on the warnings generated by the GNU C++ Compiler, especially those that are enabled with the -Weffc++ option.

This document mainly lists our deviations from the Ellemtel recommendations.

Exceptions to the Ellemtel Rules

Exception to Rule 1

Include files have the file name extension ".h".

See also Ellemtel's exception to the rule 1.

Exception to Rule 2

Implementation files in C++ have the file name extension ".C".

Implementation files in C have the file name extension ".c".

See also Ellemtel's exception to the rule 2.

Deviation from Rec. 3

An include file may contain several class definitions, if the classes are very closely related to each other. Subclass definitions are an obvious example. Sometimes, when Standard Template Library containers are used, a header file Name.h may define both class Name and e.g. class NameList that encapsulates std::list<class Name>.

Deviation from Rec. 4

In order to reduce the number of files, there typically is at most one implementation file per class definition. There should not be any linking overhead, since Maria is a monolithic program, not a library.

Exception to Rule 5

The Finnish legislation does not require explicit copyright statements. Everything that qualifies as a work is implicitly copyrighted.

Deviation from Rec. 8

Only the function declarations are documented, in a JavaDoc style supported by Doxygen. Parameter names and their descriptions are separated by TAB characters to save space in the source code.

Deviation from Rec. 9

The C-style comment separators /* and */ may be used as well. To exclude large blocks of the code during testing and debugging, the preprocessor directives #if 0 and #endif can be used just like with C.

Addendum to Rule 9

All type names are always prefixed with the appropriate keyword enum, struct or class, unless prohibited by the compiler. (Digital C++ Compiler does not allow constructor calls to be prefixed with the keyword when the result is an object, as in return class Example ();. When the result is a pointer, there is no problem: return new class Example ();.)

This rule helps the syntax highlighting rules of GNU Emacs and avoids the need of partial declarations like class Example;. When all object pointers and references are written like class Example& instead of Example&, there is no need to declare class Example separately.

Exception to Rule 10

Include file names of system libraries, such as <sys/types.h> or <readline/readline.h>, can specify subdirectories of the default include directories, as documented.

Deviation from Rec. 12

In an open-source project, there is less need to include version control system identifiers to the source files. Not including them avoids the need of recompiling when files are committed to the central repository.

Addendum to Rule 13

Names of non-static member variables are prefixed with my. Names of static member variables are prefixed with the.

Static member variables are avoided by defining static methods that return references to objects having static linkage. Publicly accessible variables can be declared as static members for efficiency.

Addendum to Rule 14

Alternatively, typedef names may be entirely in lowercase and end in the suffix _t.

Lowercase characters shall not be used in preprocessor macro names unless a library function is being renamed (#define bzero(s, n) memset (s, 0, n)).

Exception to Rule 21

All inlined member functions are defined within the class definition to reduce the amount of code.

Deviation from Rec. 23

Always leave a space between a function name and an opening parenthesis. This is compatible with the Emacs command insert-parentheses. The only place where a space is not allowed between the name and the left parenthesis is in a preprocessor macro definition.

Deviation from Rec. 24

Braces ("{}") which enclose a block are to be placed so that the opening brace is separated by a space from the preceding symbol and the closing brace is on its own line in the same column as the first symbol of the statement it terminates.

The style in which both braces are on their own lines would otherwise be acceptable, but the default behaviour of c++-mode is to apply the GNU indentation rules which would indent the statements contained in the braces twice:

while (expr)
  stmt1 ();

// same level of indentation

while (expr) {
  stmt1 ();
  stmt2 ();

// two levels of indentation, NOT ACCEPTABLE

while (expr)
    stmt1 ();
    stmt2 ();

Deviation from Rec. 28

Tabulators (with tab stops every 8 characters) should be used instead of ordinary spaces in formatting, when the code is indented by several levels. This is the default GNU Emacs behaviour. The GNU Emacs command tabify can be used to convert sequences of spaces to tabulators.

Exception to Rule 29

When there are both const and non-const access methods to member data, the non-const method may return a non-const pointer or reference.

Exception to Rule 35

In the parser or in the lexical analyser, the added flexibility and efficiency of preprocessor macros is required. Not everything can be achieved with inline functions.

Exception to Rule 46

Since we use const to indicate the "ownership" of data (when a method is passed a const pointer or reference to an object, it is not responsible of deallocating the object), there are situations where a const_cast is necessary.

Exception to Rule 48

When a switch statement has case labels for all the values of an enumeration type, there must not be a default branch. This allows the GNU C++ Compiler to warn when the enumeration type is extended with new values but some of the switch statements in the code are not updated accordingly.

Exception to Rule 50

When allocating a large block of memory in a fail-safe algorithm, calloc is safer than new, since it may return a null pointer while new might throw an exception. Since Maria deliberately avoids the use of C++ exceptions, it uses calloc and free in some occasions. This allows Maria to use a disk-based algorithm when not enough memory is available.


Return to the Maria home page.

Valid HTML 4.0!