-
Notifications
You must be signed in to change notification settings - Fork 8
Coding Guidelines
TOC
This section contains the general coding guidelines for Shawn. The following lines illustrate the basic idea of our coding style by a simple example class, but the next sections also describe our style in more detail.
class ClassNameMixedUpperLower
public:
virtual ~ClassNameMixedUpperLower();
// always a virtual destructor, some compilers dont work
// otherwise
int methods_are_stl_like( void ) throw();
// access to stored stuff is provided via two methods, const
// and writable.
// latter is indicated by _w suffix
// get_ is omitted (so usual pair is set_value(value),
// value(void)
const SomeThing& some_thing( void ) const throw();
SomeThing& some_thing_w( void ) throw();
void set_some_thing( SomeThing& ) throw();
private:
int member_variables_have_an_underscore_;
;
This section describes the Look & Feel of our source code. It contains the intending, the placement of brackets, when and where to set single spaces, and the maximal line width.
Indenting can be done either by spaces or by tabs, but 'consistently' per file. So do not mix spaces and tabs in an existing file. Instead, use what the predecessor has used. If you use spaces, indent with exactly 'three spaces' .
Brackets are consistently written in separate lines, and thus never written behind a statement. This is done for conditional expressions, loops, classes, and namespaces.
if ( a == b )
// do something
else
// do something else
for ( int i = 0; i < 5; i++ )
if ( foo == i )
// do something
class MyClass
[...]
When writing one-liners like
for ( int i = 0; i < 5; i++ )
j++;
brackets are not mandatory (albeit they can be used), but if there are nested one-liners, one should use brackets for a better readability. So better write
if ( a == b )
for ( int i = 0; i < 5; i++ )
j++;
instead of leaving the brackets out.
To enhance readability, spaces are used to separate declarations (after a comma), mathematical expressions, and before or after parenthesis.
For example, a function header looks like this:
void foo( int a, int b );
void bar( void );
An example for a conditional expression may be:
if ( a == b )
And a mathematical expression should be written as follows:
c = d + 4;
Line wrapping is done after at most 80 characters to enhance readability and portability. Note that there are also users who work in text-based environments.
If a mathematical expression must be wrapped, split it regarding to the context of the expression:
if (( a == b )
&& ( c > d || e < f
|| d > e )
&& ( g != h ))
Separators are used to enhance readability. They can be used either inside of methods to group correlated statements, or outside of methods to distinguish one method against the other.
Group correlated statements together, and separate these groups by newlines. This enhances readability because it enables reading block by block in logical sections. Moreover, the general view is improved by doing so. Have a look at the following examples.
const SimpleAppMessage* msg = dynamic_cast<const SimpleAppMessage*>( mh.get() );
if( msg != NULL )
neighbors_.insert( &msg->source() );
if( owner() != msg->source() )
INFO( logger(), "Rcvd message from '" << msg->source().label() << "'" );
return true;
return Processor::process_message( mh );
TransmissionModel::reset();
while( !aired_messages_.empty() )
MessageInfo* mi = aired_messages_.front();
aired_messages_.pop();
delete mi;
To separate one method implementation against the other, there is a delimiter between any two methods as shown in the following source.
[...]
// ----------------------------------------------------------------------
void
MyClass::
my_function( void )
throw()
[...]
// ----------------------------------------------------------------------
void
MyClass::
my_other_function( void )
const throw()
[...]
// ----------------------------------------------------------------------
[...]
The following options of [http://astyle.sourceforge.net/ astyle] might help you to reformat sourcees according to some of the guidelines above.
Put brackets on single lines: --brackets=break
Put spaces around operators: --pad=oper
Insert spaces at the insides of parenthesis: --pad=paren-in
Indent with with 3 spaces per indentation level --indent=spaces=3
This section contains rules for naming identifiers like variables and methods, and filenames. There are rules for both selecting names and spelling names.
When you think about names for identifiers, choose meaningful ones. This enhances readability, and suppresses the need for additional comments.
Hence, 'do not' write the following:
int t; // time of last reception
Instead, write it as follows:
int time_of_last_reception;
Then, use only comprehensible abbreviations for names. It is valuable to use abbreviations like 'idx' for index, or 'cnt' for count. But do not abbreviate a sentence like 'time of last reception' to 'tolr'.
In general, http://www.objectmentor.com/resources/articles/naming.htm is a mentionable article that describes naming in detail and is worth reading.
Methods and parameters are completely written in lower case characters ('a'..'z', '0'..'9', '_'). They begin with a letter ('a'..'z'). Multiple words are separated with underscores. Examples are:
void set_node_label( int );
void do_something( void );
int time_of_last_reception;
int node_cnt;
Classes are written in mixed upper and lower case characters ('A'..'Z', 'a'..'z', '0'..'9'). They begin with an upper case letter ('A'..'Z'), followed by lower case ones. Multiple words are separated by a new upper case character. If a word is a known abbreviation (like 'MAC Layer', for example), only the first character is written as an upper case one. Examples are:
class MacLayer;
class SimulationController;
class HelloWorldProcessor;
If class members can be accessed (per set or get) via methods, these methods follow a certain naming rule. All setters have the prefix *'set_**' :
void set_some_thing( SomeThing& obj ) throw();
Getters 'do not have' any prefix. To distinguish writable and constant getters, writable ones get the suffix '_w*' :
const SomeThing& some_thing( void ) const throw();
SomeThing& some_thing_w( void ) throw();
Private members of classes always end with an underscore:
int private_member_of_a_class_;
As a side effect, variable names in setters and constructors can easily be chosen.
void set_value( int value )
value_ = value;
Sourcefiles are named after the particular class (e.g., the files simulation_controller.* contain the class SimulationController). Like naming methods and parameters, filenames are completely written in lower case characters ('a'..'z', '0'..'9', '_'). They begin with a letter ('a'..'z'). Multiple words are separated with underscores.
File extensions are *.h for headers, and *.cpp for source files.
When creating directories, there are the same rules as for files. Use only lower case characters or digits, separate by using the underscore, and 'do not' use spaces.
The usage of \#define
should be avoided, because there are
enough alternatives available in C++ (const (const int foo = n
),
inline functions, templates), and macros also do not obey
scopes or type rules.
So do not use macros unless it is absolutely inevitable. Especially, avoid using macros in header files. If at all, use them in source files where they are only applied strictly local.
Make yourself familiar with the programming language C++, and use available constructs instead of reinventing the wheel. Especially, make use of the STL, their containers and iterators. Use streams and strings. If something is worth made generic, use templates.
Always write 'virtual destructors' :
virtual ~Class();
If a method of a class does not modify the state of an object, declare
it as const
. As const objects are often used in Shawn, this
increases usability for developers.
Each method of a class must specify the type of potentially thrown exceptions. If no exceptions are thrown, use the empty specification. Examples are:
const ProcessorKeeper& processor_keeper( void ) const throw();
ProcessorKeeper& processor_keeper_w( void ) throw();
virtual void run( SimulationController& ) throw( std::runtime_error ) = 0;
All comments and all documentation are written in English, because Shawn is used in an international environment.
Header files are completely documented in doxygen-style to be able to automatically generate documentation in HTML, pdf, or the like. See http://www.stack.nl/~dimitri/doxygen/manual.html, for example, for details. Thereby the class itself, each method, and each parameter must be described.
The description of the class starts with a brief description of what the class is supposed to do. This is an one-liner that is used together with the doxygen keyword \ brief . Then, a detailed description follows. It contains the general behavior of the class, the context in which it is used, potential usage hints (e.g., with examples), and so on.
Next, methods must be described. If suitable, they are grouped with the aid of the doxygen keywords @name , *@* , and *@' . Then, for each function the purpose and usage are documented. Optionally, the description can be started with an one-liner and the keyword \ brief . At last, all parameters (if there are any) and the return value (if not void) are documented.
Then, the class members are documented, generally with a short one-liner that describes the purpose of the value and in which context it is used.
However, here is a skeleton of a general header file:
/** \brief Short Description (one line)
*
* Detailed description (multiple lines).
*/
class DoxygenExample
public:
///@name Constructor/Destructor
///
/** constructor description, optionally with \brief
*
*/
DoxygenExample();
/** destructor description, optionally with \brief
*
*/
virtual ~DoxygenExample();
///
///@name Getters and Setters
///
/** function description, optionally with \brief
*
* \param value brief description
*/
void set_value( int value );
/** function description, optionally with \brief
*
* \return brief description
*/
int value( void );
///
private:
/// purpose of value
int value_;
In general, give rough descriptions of what you are doing and why. Do not comment obvious lines like
a += 1; // add one to a
Then, use //
for documentation, also for multi-line comments
(note that this rule holds only for in-source documentation):
// first line of comment ...
// ... followed by the second line.