======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 [[https://en.wikipedia.org/wiki/Indent_style#Allman_style|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 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 [[http://www.emacswiki.org/emacs/SmartTabs|"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 [[https://raw.githubusercontent.com/jcsalomon/smarttabs/master/smart-tabs-mode.el|smart-tabs-mode.el]] and [[https://elpa.gnu.org/packages/cl-lib.html|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)
[[http://vim.wikia.com/wiki/Indent_with_tabs,_align_with_spaces|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 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);
};
=====Links====
A lot of these guidelines are inspired by the style guide from the [[http://ardour.org/styleguide.html|Ardour project]].