Description
coding.doxys::Coding/Layout Recommendations & Tips
( Page )
Coding Standards and Eclipse
If you are working with eclipse, there's a coding standard file available within
the internal section. It is called
peano-stylefile.xml.
Nomenclature and Formating
General
- Blanks have to be used instead of tabs (hint: configure eclipse such that blanks are inserted instead of tabs).
- The length of one line should not exceed 80 characters
- Indention is two blanks ("Einruecktiefe ist zwei Leerzeichen").
- Each namespace (package) has its own directory.
- Including has to be done using the complete (relative) path (such as
#include "dir/file.h"
). Attention: This principally allows for using the same class name in different packages; nevertheless, this should be avoided!
- Each class has a header file (.h) and an implementation file (.cpp). If the class is a templated one, there only is a header; nevertheless, the implementation should be split apart into a .cpph file which is included by the .h file.
Layout
- All nestings have to be marked by braces (i.e. "{}"), even if it would syntactically not be necessary.
- Encapsulated Code has to be indented in order to mark logical nesting. The closing brace at the end is at the original indention depth position:
- Compiler instructions such as
#ifdef .. #endif
that surround methods are to be indented just like the method itself:
#ifdef X
class A {
public:
...
#ifdef Y
void methodB();
#endif // Y
};
#endif // X
|
Header Files
- Header files have the suffix .h.
- Header files may contain:
- a type definition or a template,
- arbitrary many type definitions,
- declaration of functions,
- inline functions.
- Each header file defines a preprocessor definition of the form
_PACKAGENAME_TYPENAME_H_
to avoid multiple inclutions.
- Namespace adherence are realised via explicit declarations and not via brace nesting. This reduces indentions depth.
- Forward declarations for pointer or reference attributes have to be used in order to avoid inclution cascades. The real inclutions are done in the implementation (.cpp) files. This is not necessary/useful for templated classes, as their implementation is included in the header files.
Implementation files
- Implementation files have the suffix .cpp (except for templated classes, where .cpph has to be used and included into the header).
- Implementation files must not contain declarations.
- The namespace adherence is done explitely for every construct and not via a brace nesting.
- Global variables are not allowed or have to be realised as static constant attributes, respectively. Thus, the variables are all semantically connected to a type.
Nomenclature
- Documentation and coding has to be done in English.
- Names have to be self-explaining.
- Type and template names start with a capital letter.
- Variable names start with a small letter.
- Attribute names start with an underscore followed by a small letter.
- Constants start with a capital letter.
- Packages start with a small letter.
- Names in general do not contain abbreviations.
- No Hungarian notation is used.
- Words inside an identifier start with a capital letter.
Classes
- All classes offer at least one constructor (to avoid compiler-generated constructors).
- All classes offer a destructor.
- If a class has a virtual function, it has to a have a virtual destructor.
- Non-virtual functions must not be overwritten.
Methods and functions
- The initialisation lists in the constructor(s) have to be ordered as in the declarations.
- Initialisation lists have to contain all attributes (not only a subset).
- Methods and functions have no variable argument lists.
- Whenever possible, the const identifier has to be used (for arguments and methods/functions themselves!).
Variables
- Variables have to be declared just before their usage (latest possible).
std::string
has to be used instead of char arrays.
Documentation Guidelines
In Peano, we follow a ''It's all in the code'' and ''document immediatly'' policy. Consequently, the whole documentation of the Peano software is threefold:
- The papers describe the foundations and ideas of the algorithms implemented within Peano. (what is available)
- The dissertations give an en detail description of this functionality. (what is available, why is it available, how is it implemented)
- The headers of the code describe the realisation. (how is something implemented, what are the realisation alternatives, what is the rationale).
To generate the code, we use DoxyS (http://www.doxys.dk).
- File and class comments: Each header file contains exactly one class (see above). In front of this class declaration, a short comment concerning the targets/goals of the class should be put.
- Header vs. implementation files: All documentation has to be put in front of the declaration (in header files). Implementation files do not contain any doxys documentation block.
- Complex collaboration: The key interest for the analysis of a program is to understand the basic work steps which might be very complex. These can be facilitated by the use of UML diagrams that may be generated by a tool (such as dia, e.g.) and exported to some picture format that is then included via doxys (@image tag).
- Operations:
- Use the @param and @return tags for documenting operations. Document either all parameters of an operation or none, since doxys generates irritating warnings when only parts of the parameters are documented.
- Try to use the @see tags. The corresponding links are very useful for reverse engineering tasks of newbees in the program.
- The operation comment should contain at least a black box description of the semantics of the method. One has to decide whether or not to describe pre- and post-conditions. Please note that the tags @pre and @post from doxygen are not (yet) valid in doxys (@pre specifying even sth. else, namely a section of text that shall be formatted as typed).
- Interprocedural comments: Interprocedural comments are a mine field of coding standards. There are different groups. Some consider the refactoring techniques (see Fowler et. al.) as a major point of concern and, thus, reject any comments inside of operations. Operations that would need such comments are, in their opinion, either too long (and should be splitted up) or the constructs in use do not have useful names. Please really try to not use comments inside implementation!
- Constants, attributes, and variables: All of them have to be documented in the header file of the corresponding class.
- Rationales: We use the definition of rationales (and design rationales, resp.) of Bruegge: Rationales are all argumentations and ideas that have contributed to the current state of the system. This contains:
- problems, problem definitions and aspects that have been considered,
- alternatives that have been considered, tried and/or rejected,
- decisions taken in this context,
- criteria that contributed to these decisions,
- persons who took these decisions
- the complete process of argumentation, Whenever possible, one should insert this information concerning the "why does the program source code is as it is". This explicit putting into comments will ease up understanding of the program for other users/developers as well as for the original author himself (if he needs to reconsider parts of the code after more than some weeks, e.g. ;-)).
- Understanding names: Due to useful features such as auto-completion and easy-to-use cut-and-paste mechanisms in modern IDEs, variable/method/class names may get (long) names that explain their basic ideas/concerns. Try to avoid short but cryptic names!
- Hungarian notation: Do not use Hungarian notation! This way of giving an extra prefix describing the type is not too useful in object oriented programs, as "everything is an object".
- Images and Formulas: Include images and formulas wherever possible. They make life much easier.
Avoid implicit typecasts
Obviously gcc does not complain if you do something like
double myDouble;
int myInt = 1;
myDouble = myInt;
|
This lead to some bugs which are really hard to find. In particular if you use the linear algebra toolbox with vectors of different types. Consequently, we compile with the flag -Wconversions
switched on always. In this mode, gcc detects type conversions such as the one from above.
The bad news about this compile flag is that we have to insert tons of static_cast
into the code everywhere. However, that is better than having bugs.
The standard C++ library
If you use the standard library of C++, be aware of a couple of things:
- Please, never use the
using namespace std;
statement.
- Ensure that you add the
std
:
prefix everywhere where needed. Some installations allow you for example to write abs
, while others expect std
:abs
. Please code with the latter variant always.
Coding for different compilers
As HPC guys, the Peano developers have to ensure that the code runs on several supercomputers. With tailored compilers for different architectures, we support the following compilers:
- GNU compiler suite. Version not older than 4.0. KAUST and LRZ Linux-Cluster, e.g.
- Intel compiler suite. Version not older than 10. Infinicluster and Altix, e.g.
- CLX compiler suite. BlueGene/P, e.g.
Please check regularly whether your modifications pass the compilers from above. Below is a list of experiences for troubleshooting. Please augment this list and share your experience.
- CLX complains about incorrect pragmas, about NOSTRICT options, etc. Ensure that you have used the
-qpack_semantic=gnu
switch and that you have modified your CompilerSpecificSettings.h file in the utils directory accordingly.
- CLX complains about
A template dependent name that is a type must be qualified with "typename"
. CLX requires many typenames in the implementation files to be qualified with the typename keyword. See for example Checkpoint::readCheckpointHeader. Try to add a typename before the type (its usually a type embedded into the template).
- GCC complains about
prototype for 'xxx' prototype for 'yyy'
. If you followed issue two, you just modified your template implementations. As a result, GCC might complain about your header. In this case, go back to the implementation and provide two alternatives of the implementation. Embed them into the define CompilerCLX
and add an include statement to the implementation that references CompilerSpecificSettings.h
- CLX complains about my namespaces. Unlinke GCC and the Intel compiler, CLX does not accept that the superclass namespace it given relatively to the class' own namespace, i.e. for a class A::B::C inheriting from class A::D::E, a statement
class A::B::C: public D::E
does not work while class A::B::C: public A::D::E
works. Consequently, always specify the full qualified superclass name.
- CLX complains about a template argument being a template itself. If you write a type-generic class with an argument 'class T' and T is in turn a template again, GCC and the Intel compiler do not care. Things are different with the CLX. This compiler has to know a priori that the template argument T is in turn a template, and it has to know the exact types used by the superclass template. To make things a little bit more complicated, the superclass types have to have a different name than the actual template's types. Finally, GCC and Intel do not support this more detailed template handling, and, thus, the whole superclass modifications have to be embedded into
CompilerCLX
.
- CLX or ICPC complain about
"XXX" has a conflicting declaration
. Ensure that the variable depending on a template type does not have the same name as the template type itself. The statement Cell Cell
, e.g., defining a variable of the name Cell
is accepted by gcc, but the Intel compiler and CLX do not accept such a statement.
If you encounter problems with the CLX, have a look at the following documents:
Source
The documentation for this Page was generated from the following file: