BEAST - Coding Style

Tim Janik
Stefan Westerfeld

Document revised: Tue Feb 21 00:28:59 2006

This document provides a list of rules that need to be followed when writing code that become part of BEAST. As the development of a consistent coding style is work in progress, these rules are not comprehensive. We also acknowledge that not all code that is part of BEAST currently follows this coding style guide.

However, everything that is in this file has been negotiated, and new code must follow each of these rules. Where no explicit rule exists, try to follow what existing code does, or ask, when in doubt.

Table of Contents

1 Indentation and Formatting

1.1 Function Return Types are written on a Separate Line

This rule only applies for the implementation of functions, not for the function prototype.

Reasons:
  • This makes reading the actual function name quickly easier, because all function names start at the same column

Code Example:
bool
does_the_universe_still_exist()
{
  return true;
}

template<class T> bool
frobify_two_things (const T &thing1,
                    const T &thing2)
{
  [...]
}

class Foo
{
  bool m_alive;
public:
  static bool
  is_any_foo_alive()
  {
    [...]
  }
  bool
  is_alive() const
  {
    return m_alive;
  }
  [...]
};

1.2 Multiline Comments

There are generally two kinds of multiline comments: documentation comments and non-documentation comments. The following code example show that documentation comments get an extra line, which starts the documentation comment, whereas ordinary comments may not have an extra new line.

Code Example:
/**
 * This function is checks whether the universe still exists; however it is
 * unclear how a caller could call it if the universe no longer exists, 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;
}

1.3 References and Pointers are declared next to the Identifier

Reasons:
  • When declaring more than one variable, the pointer / reference symbol (* or &) will only affect the first declaration. Thus it is better to put this symbol next to the identifier, to avoid mistakes.

Code Example:
struct Foo
{
  char    *x;
  string  &y;
  Foo     *z;
};

void bar (Foo          &foo1,
	  const string &y)
{
  char *x, *y, *z;
  const string &bar = foo1.y;
}

1.4 Constructor Initializer Indentation

The initializers following a constructor should be indented like this:

Code Example:
class Foo : public Bar
{
  int	      m_x;
  int	      m_y;
  vector<int> m_some_integers;
public:
  Foo (const string &bar_name,
       int           x,
       int           y) :
    Bar (bar_name),
    m_x (x),
    m_y (y),
    m_z (x * y)
  {
  }
  [...]
};

It is important that the colon (":") is placed after the constructor declaration, whereas the member initializers (or chained parent constructors) are placed on the next lines.

1.5 Data members in classes are declared before functions

Reasons:
  • By using this rule, it becomes easier to read the data members a class has, because they are always declared at the beginning of the class.

Code Example:
class AudioDistortion
{
  double m_amount;
public:
  void
  set_amount (double amount)
  {
    m_amount = amount;
  }
  void
  distort_block (vector<float>& block)
  {
    [...]
  }
  [...]
};

2 Names

2.1 Functions, Methods, Members, Arguments and Local Variables are written as lower_case_underscore_names

Code Example:
guint
add_one (guint some_number)
{
  return some_number + 1;
}

2.2 Type Names are written as MixedCaseNames

Code Example:
typedef float SampleType;

class HashTable
{
  [...]
};

2.3 Class Members are prefixed with m_

Reasons:
  • This is meant to distinguish class members from local variables, arguments or function names; for a constructor for instance you often get an argument x, and want to initialize the corresponding member; instead of writing Constructor (int x) : x (x) which may be misleading, you can write Constructor (int x) : m_x (x)

Code Example:
class IntArray
{
  vector<int> m_integers;
public:
  IntArray (guint n_integers) :
    m_integers (n_integers)
  {
  }
  [...]
}

3 C++ References

3.1 Out Arguments of Functions that are Non Object Types are passed by Pointer, not by Reference

Reasons:
  • This is meant to improve the readability of the code (you can see that the value is being modified)
  • It makes understanding the code easier for C programmers, which may not be used to references

Every output argument that has a type that can be found in C (pointer, float, int, ...) may not be passed by reference, but must be passed by pointer. This rule does not apply to C++ objects which may be passed by reference.

Code Example:
bool
parse_xyz (const string &input,
           float        *x,
	   float        *y,
	   float        *z)
{
  [... C++ Code that parses the input string, returns true
       on success and fills x, y, and z with the parsed values ... ]
}