Coding Guidelines

= Coding Guidelines =

Herein we're addressing some guidelines for making direction and design decisions during project development.

Coding Style
This section provides a list of rules that should be followed when writing code to become part of Beast or Rapicorn. The development of a consistent coding style is work in progress, so these rules may not be comprehensive. Also not all existing code might follow these rules, in these cases it's usually a candidate for cleanups for which patches are happily accepted.

However, new code should generally follow each of these rules and if no explicit rules exists, try to look at existing practice or ask, when in doubt.

Names and Identifiers
Names and identifiers should ideally be self explaining. Good terminology is very important for readable code, so it pays off to invest some thinking time into picking good variable names. This is even more important for functions or class names that become part of a public interface and need to maintain backwards compatibility.

Identifiers
Functions, methods, members, arguments and variables are written in lower case, using an underscore as word separator. Example: lower_case_underscore_names
 * Rationale: Without special training, many people recognize lower case words with separator space better than CamelCase words.

Type Names
Class names, type definition and aliases use "camel case", where words are spelled with one leading upper case letter and placed adjacently. Example: GtkScrolledWindow
 * Rationale: While less readable, using CamelCase for type names allows easy differentiation between type names and identifiers. Type names generally occour less often than identifier names which mitigates the readability impact. Also used in GTK+ coding style.

Constants
Constants, enum value names and macros are spelled with underscored in all upper case. Example: BSE_ERROR_FILE_NOT_FOUND.
 * Rationale: This is done for easy differentiation from type names and especially assignable identifiers. Also used in GTK+ coding style.

Indentation and Formatting
The following describes several styles of indentation and formatting to improve code readability and navigation.

Newlines around Function Bodies
Function implementations spanning multiple lines should use a newline preceeding the function name. This generally pushes function return type, visibility keywords or template args ont their own line. Similarly, the function body should be enclosed by curly braces on their own lines. Exceptions are empty function bodies where both curly braces should go on the same line. Example: template bool			// newline before function name frobify_two_things (const T &thing1, const T &thing2, bool repeat) {					// single line for opening curly brace // function body }					// single line for closing curly brace void dummy_callback {}					// empty function body
 * Rationale: Function names are easily recognized as they start a line. Also used in GNU Coding Style.

Multiline Comments
There are generally two kinds of multi-line comments: documentation comments and non-documentation comments. Documentation comments should start with "/**" on a seperate line, while ordinary comments should not start with an extra empty line. /** * This function checks whether the universe still exists; it is unclear however how * a caller could call it if the universe ceased, so you probably won't need it. */ bool does_the_universe_still_exist { /* We can assume that if the program still runs, then the universe can * not possibly be gone. */ return true; }
 * Rationale: Documentation comments need to be parsable by Doxygen, ordinary comments don't need to waste space.

Declaring Pointers and References
In variable declarations, operators for references and pointers should be declared next to the identifier. This matches the C++ parsing rules which will only attribute the operator to the first identifier. Arguments in function declaration should follow he same style for consistency. Example: int *pointer1, a_number, *pointer2; void function (int *ptr1, Object &ref);
 * Rationale: Putting the operator adjacent to the type might lead to misinterpretations in declarations of multiple variables.

C++ References
Output arguments for functions that are not object types are passed by pointer, not by reference. This may be contrary to other common C++ uses, but is consistent with how output arguments must be passed in plain C. bool parse_xyz (const std::string &input,          float             *x,           float             *y,           float             *z) { *x = *y = *z = 0; // parse input, assign x, y, z }
 * Rationale: Generally using pointers for output arguments is meant to improve the readability of the code (output arguments are clearly labeled in function calls) in a mixed C/C++ code base.

Declare Data Members First
In class definitions, data mambers should be moved to the start of the class definition where possible. Usually, data members should be private which is achieved by placing these at the top of a class definition before opening a public: section. Example: class NodeLink { NodeLink *m_prev, *m_next; public: void prepend (NodeLink *other); void append (NodeLink *other); };
 * Rationale: Grouping the data members at the start of a class definition aids understanding by emphasizing the data structure aspects of the class. It also correlates syntactically with declaring class members as private.

Data Members are prefixed
Data members declared in class definitions should generally be prefixed with m_. Example: class IntArray { int        m_initial_size; vector m_integers; public: IntArray (uint n_integers) : m_initial_size (n_integers), m_integers (n_integers) {} }
 * Rationale: The prefixing is meant to distinguish class members from local variables, arguments or function names. It also helps to prevent ambiguations for constructor arguments which are often named similarly to some data members.

Constructor Initializer Indentation
Initializer calls in constructor definitions should go on their own lines, the colon following the constructor function declaration should be followed by a newline. Example: struct Foo : public Parent { int  m_x, m_y; Foo (int x, int y) : Parent (x * y), m_x (x), m_y (y) {} };
 * Rationale: This notation is our preference for readability.