DrumGizmo Code Styleguide

Code is written once by one person but read many times by many people.

What this essentially boils down to is; don't make syntactic short-cuts that makes it easier to write the code if it makes it harder to read the code.

Always write comments to logical blocks in the code that explains for example what a for loop does or how a couple of function calls interact.

Never make if statements or loops that can't be displayed within a single screen. If they are this long rethink the code structure.

Functions should likewise be possible to show on a single screen. If longer split the function into several smaller functions. This will make logic of the code stand out and ultimately make it easier to read the code.

Always use C++11 code.

Curly Braces

Use BSD/Allman style. This basically boils down to 'curly braces always on a new line':

namespace Foo
{
 
void function()
{
  for(int i = 0; i < 100; ++i)
  {
    foo(i);
  }
}
 
} // Foo::

This code will make emacs behave in this manner:

(setq c-default-style "bsd" c-basic-offset 4)

Vim apparently applies this behaviour by default.

Always use curly braces on if statements… even one-liners…

if(this)
{
  then_that();
}
else
{
  else_this();
}

Switch/case

Plain switch case:

switch(value)
{
case 1:
  break;
case 2:
  break;
}

If switching over an enum never use 'default' since this will make the compiler unable to warn about missing cases that arise if the enum is expanded.

If a variable needs to be declared inside a case further braces are needed. They should be indented as follows:

switch(value)
{
case 1:
  {
    int my_value = 42;
  }
  break;
case 2:
  break;
}

Note that the break is still positioned outside the closing brace to make it easy to spot missing breaks.

Classes

Use protected instead of private as this makes unittesting easier (or at all possible). Use inheritance an initialisations on seperate lines with the colon/comma in the beginning of the lines.

By example:

class MyClass
  : public SomeBaseClass
  , public SomeOtherBaseClass
{
public:
  MyClass(int some_member);
 
protected:
  int some_member;
};
MyClass::MyClass(int some_member)
  : some_member(some_member)
  , SomeBaseClass(some_member)
  , SomeOtherBaseClass(some_member)
{
  // ...
}

If methods are overloaded always use the 'override' keyword and write a comment in the header file where the original method were:

class MyClass
  : public SomeBaseClass
  , public SomeOtherBaseClass
{
public:
  // From SomeBaseClass
  void someMethod() override;
  void someMethod2() override;
 
  // From SomeOtherBaseClass
  void someOtherMethod() override;
  void someOtherMethod2() override;
};

Member variables should always be initialized in the header file, and should use the curly-brace notation:

class MyClass
{
private:
  int some_member_variable{}; // default initialize to 0
  int start_position{42}; // default value decided by the developer
  static constexpr int step_size{2}; // and use static constexpr whenever possible instead of defines
  std::array<int, 5> buckets{}; // default initializes all values at once
};

Pointers and References

Pointer stars and reference ampersands must be placed to the left without space after the type:

int a = 42;
int* b = &a;
int& c = a;

Indentation

Use "SmartTabs", ie. tabs for indentation and spaces for alignment.

--->// Tab size: 4             ->// Tab size: 2
--->if(foo)                    ->if(foo)
--->{                          ->{
--->--->char q[2][2] = {0, 1,  ->->char q[2][2] = {0, 1,  // "0" and "2"
--->--->................2, 3}; ->->................2, 3}; // remain aligned
--->}                          ->}

With smart-tabs the tab-width doesn't affect the way the code is aligned which makes it up to the individual developer to choose the tab-width of his or her taste.

Download smart-tabs-mode.el and cl-lib into the .emacs.d/lisp folder and add the following lines to the .emacs file:

(add-to-list 'load-path "~/.emacs.d/lisp/")
(load-file "~/.emacs.d/lisp/cl-lib-0.5.el")
(load-file "~/.emacs.d/lisp/smart-tabs-mode.el")
 
(autoload 'smart-tabs-mode "Intelligently indent with tabs, align with spaces!")
(autoload 'smart-tabs-mode-enable "smart-tabs-mode")
(autoload 'smart-tabs-advice "smart-tabs-mode")
(autoload 'smart-tabs-insinuate "smart-tabs-mode")
 
(smart-tabs-insinuate 'c 'c++ 'java 'javascript 'cperl 'ruby 'nxml)

In Vim is should be possible to use Smart-Tabs mode using the following lines:

:set noet sts=0 sw=4 ts=4
:set cindent
:set cinoptions=(0,u0,U0

Include guards

Use

#pragma once
 
... code ...

and NOT the old-school

#ifndef DG_HEADER_FOO_H
#define DG_HEADER_FOO_H
 
... code ...
 
#endif//DG_HEADER_FOO_H

Pointers to nowhere

Use the new nullptr instead of the C-style NULL.

Incrementing

Pre increment integers and iterators instead of post increment.

Like this:

int i = 0;
++i;

Iterators

Always range-based for loops and in cases where these are not available at least use the auto keyword for the iterator type:

std::vector<int> my_vector;
for(auto an_int : my_vector)
{
  foo(an_int);
}

Naming

All names MUST ALWAYS be good, non-short and descriptive.

int w = 70; // <-- BAD
int window_width = 70; // <-- GOOD

The following naming schemes apply:

classes and structs:

class UpperCaseCamelCase
{
};

methods and functions:

void lowerCaseCamelCase()

variables and members:

int lower_case_snake_case = 42;

defines:

#define SHOUTING_SNAKE_CASE 42

const

The rule about when to use const is “as often as possible”. All function or methods taking objects as arguments should be passed as references and if the function or method does not modify them the argument must be declared const.

void openFile(const std::string& filename); // <-- Function doesn't modify the argument.
void getPath(std::string& path) const; // <-- Method doesn't modify it's object but does modify the argument.

The const keyword is positioned to the left of the type which makes the distinguishing between a pointer to a const object and a const pointer to an object easier.

const Foo* foo // <-- a pointer to a const Foo object.
Foo* const foo // <-- a const pointer to a Foo object.
const Foo* const foo // <-- a const pointer to a const Foo object.

Doxygen

All public methods on classes must be documented with doxygen. Protected/private methods should also be documented but not nessecarily with doxygen syntax. The doxygen style to be used is “//!” for comment style and “\” as keyword marker:

//! This is a class
class SomeClass
{
public:
  //! This is a method.
  //! \param foo The foo argument is an integer.
  //! \param bar The bar argument is a boolean.
  //! \return This method returns a float.
  float method(int foo, bool bar);
 
protected:
  // Internal utility method for doing stuff on the coordinate (x, y).
  void doStuff(int x, int y);
};

A lot of these guidelines are inspired by the style guide from the Ardour project.

dev/dg_code_style_guide.txt · Last modified: 2024/07/26 10:46 by deva
Trace: dg_code_style_guide
GNU Free Documentation License 1.3
Valid CSS Driven by DokuWiki Recent changes RSS feed Valid XHTML 1.0