Inkscape Coding Style Guidelines
For discussion, please see Coding Style in Wiki.
Indention
We have decided to use 4 spaces as a tab for the project.
Files should include a modeline specifying the tab stops and indentation character specified by the standard.
public/protected/private declarations should be indented flush with the enclosing block's parent; for example:
class Fleep {
public:
...
};
Labels and case statements should be fully indented (however, do not use goto unless you can articulate clearly and defensibly why you ought not to use it):
void gromzala(int a)
{
...
somelabel:
...
goto somelabel;
...
}
switch (fogo) {
case ROMPH: {
...
break;
}
case OOGA: {
...
break;
}
default: {
...
}
}
Case statements should always have blocks attached.
Vertical Spacing
Don't collapse statements to single lines.
- Multiple statements on a single line make stepping and setting breakpoints difficult when debugging.
- We're no longer working from teletypes
Inserting blank before/after a chunk of code can be useful for indicating a conceptual grouping.
Spacing
- Space after commas
- Space after keywords that precede expressions (if, for, while, etc.)
- Space around expressions in parenthesis if the expression is binary or ternary
- NO space around an expression used as a subscript
- NO space between a function (or macro) and its argument list
- NO space before ';' except when used with
for(in which case there should be space on both sides) - 'return' should not use parenthesis around its accompanying expression unless the expression is complex and it helps clarity
Examples:
func(a, b);
if (var) {
...
}
if (func(a, b)) {
...
}
if ( a != b ) {
...
}
for ( a = 0 ; a < b ; a++ ) {
...
}
while (!( a + b )) {
...
}
var = ( a | b ) & c;
func(( a | b ), c);
var = (int)( a + b );
var = array[func(a, b)];
func(array[a + b], c);
return a + b;
return ( a ? b : c );
Single variable per declaration.
- Makes things a little more explicit.
- Simpler to change type on a single variable if needed.
- Better diffs for adding/removing variables.
Space between a type name/qualifier and pointer/reference sigil
- e.g. "char *" and "int &", versus "char*" and "int&"
- Doing so promotes better understanding of C/C++'s parsing rules for
cases like
int *a, b: the sigil applies only toain that example, not tob. - It is sometimes argued that the sigil is part of the type, but even primitive types may have space between their tokens (e.g. unsigned long).
Placement of const
Although in the past it has been common to place const' at the
beginning of they type whenever C/C++ allows, this has led to
experienced programmers misunderstanding int * const *p': people
wrongly think it means that p is a constant pointer, when in fact
p is a non-constant pointer to const pointers to non-const int's.
Consequently, we will switch to consistently placing the const after
what it modifies: just as C/C++ leaves us no choice but to write int *
const for a const pointer to (non-const) int, for consistency we also
write int const for a const int.
Wrapping
On whether the operator goes at the end of the broken line or the beginning of the continuation:
- Comma operator goes at the end of the line before the break.
- Dot operator goes at the beginning of the continuation.
- (Of course, the dot operator isn't usually a good breaking point.
More generally, try to break in as few sub-trees of the parse tree
as possible try to avoid breaking in the middle of a parenthesized
expression, break at
&&in preference to==in preference to+in preference to*.) - If the expression contains a mix of operators acting at a "similar level" (e.g. a condition involving both && and ||), then putting those operators at the beginning of the continuations makes it much easier for humans to parse:
( ( ( foodlesplork()
&& bartlecapple() )
== ( fork < spoon ) )
&& ( ( cat + mouse < dog * rat )
|| eats(cat, mouse) )
&& !on_fire(house) )
is easier to parse than
( ( ( foodlesplork() &&
bartlecapple() ) ==
( fork < spoon ) ) &&
( ( cat + mouse < dog * rat ) ||
eats(cat, mouse) ) &&
!on_fire(house) )
In cases where the precedence is easier to see without help, putting the operator at the end of the line can make it easier to see the similarities & differences between the operands by having them line up vertically:
( ( foo.fork == bar.fork ) &&
( foo.spoon == bar.spoon ) &&
( foo.knife == bar.knife ) )
The above still uses the general principle of using extra whitespace to
assist distinguishing the precedence of == and
&&. This works well in the above example (with multiple
lines ending in the same operator), though in other cases the extra
space can make it harder to read.
The Preprocessor
DO NOT USE #ifdef UNLESS ABSOLUTELY NECESSARY. It leads to code rot as the surrounding code is changed, but the disabled code is not updated.
If you must disable a section of code temporarily, use plain "if" if at all possible. That will ensure that the code is still checked by the compiler, even though it will not be part of the resulting binary (the compiler will optimize out dead code chunks).
Also, never EVER do this:
#ifdef SOMETHING some code #else some code (only slightly different) #endif
Often, fixes made to one piece of code will be missed in the other, and the two pieces of code may drift apart, introduced or unfixed bugs unnoticed for months...
If you do have to use #ifdef for something, absolutely try to minimize the amount of code within it. Make the remaining code as generic and portable as possible.
Declarations & Definitions
Use standard function declarations and definition all on a single line.
- all modern IDEs can track down functions
- Anyway, in C++ methods are normally qualified at their definition and nowhere else (unless you like playing with method pointers).
Braces
Compact braces should be used under normal circumstances. For example:
if (flamoba) {
...
} else {
...
}
However, if the leading if/while/for expression spans more
than one line, then the brace should be on a line by itself, in order to
make clearer which lines are part of the expression and which lines are
part of the block.
[This multi-line exception is particularly important if we choose an indentation quantum of 4--5 spaces, and not very important at all if the indentation quantum is 2-3 spaces -- in which case the expression continuation will already be more indented than the lines of the block.]
Example
if ( grarzbo(mof, glorble(gronk), fofo, obo,
fronk, bleeb) &&
grarzbo(fom, 42, 0, 0, 0, 0) )
{
...
} else {
...
}
Brace goes on separate line for function definitions, to placate the parser used by add-change-log-entry.
Not required by function-menu, so perhaps we could fix the add-change-log-entry parser by copying from that used by function-menu.
Block statements should have braces when possible.
- Even single-line bodies can benefit. Since, among other things, single-line bodies often don't remain single lines forever.
Naming by Example
NamespaceName ClassName CONSTANT_NAME publicMemberFunctionName _protectedMemberFunctionName _privateMemberFunctionName public_static_member_function_name _protected_static_member_function_name _private_static_member_function_name _member_name function_name variable_name
C++
Class Design Consistency
Class definitions: at most one public: block, followed by at most
one protected: block, followed by at most one private: block.
- General principle supporting this: put the most significant stuff first; if the reader cares, they can keep reading.
- If, under that rule, you feel the need to use multiple public/protected/private blocks, it's a strong indicator that you really need to refactor the class into smaller ones instead.
Namespace blocks do not introduce an additonal indention level
Always define default, private, un-defined copy ctor and operator = .
As a rule, all C++ classes should have an explicit copy constructor and
assignment operator (operator =). Instead of defaulting to the standard one,
any classes that don't already have them should have the two declared in the private:
section of the class, but never actually have those functions defined.
class Foo {
...
private:
Foo(const Foo& other); // no copy
void operator=(const Foo& other); // no assign
};
When a class has a destructor, always make it virtual. Just to be on the safe side. For an explanation, please see "When should my destructor be virtual?" on C++ FAQ Lite.
class Foo {
...
virtual ~Foo();
...
};
Non-trivial inline methods (i.e. other than one-line trivial mutators/accessors) should be placed outside the class definition (though still in the header file), e.g.:
class Fubo {
public:
void torfle(int morp);
};
inline void Fubo::torfle(int morp)
{
...
}
- This is partly to discourage the use of non-trivial inline methods, and partly to make it easier to make them non-inline and move them to a .cpp file.
Namespace using
- Don't use
using namespace'. Ever. Just don't. You'll be setting yourself up for major pain in the future when someone adds a symbol to that other namespacce that collides with one in yours. -
using' an individual class or function name is okay, but please don't do it at the file scope in a header file. - If you find yourself needing
using' at file scope in a header file, consider a typedef instead.
Templates
Template keywords should get their own line, so the actual function or class name is easy to find next to the mess of angle brackets.
For example:
template <class T>
void pobi(T &ubba)
{
...
}
or, in the case of a template specialization:
template<>
class Roga<Florm> {
...
}