Skip to content
This repository has been archived by the owner on Aug 25, 2020. It is now read-only.

Coding Guidelines

Marvin Frick edited this page May 28, 2013 · 1 revision

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_;
 ;

General Style

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

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

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.

Spacing

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;

Wrapping

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

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.

Inside Methods

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;
Outside Methods

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()
  
      [...]
  
   // ----------------------------------------------------------------------
   [...]

Using Astyle

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

Naming

This section contains rules for naming identifiers like variables and methods, and filenames. There are rules for both selecting names and spelling names.

Selection of 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.

Spelling of Names

Methods and Parameters

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;
Class Names

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;

Prefixes and Suffixes

Getters and Setters

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 Member

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;

Files and Folders

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.

Programming Behavior

Using Macros

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.

Using the Range of the Language

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.

OOP

Destructor

Always write 'virtual destructors' :

virtual ~Class();

Const Member Functions

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.

Exception Specification

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;

Comments

Language

All comments and all documentation are written in English, because Shawn is used in an international environment.

Header Files

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-Source Documentation

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.