Comment Hierarchy
The C++ language uses two comment styles: The older C-Style block comments that start with /* and end with */, and the newer C++ Style line comments that start with // and run to the end of the line. The block comments can accommodate any number of lines while the line comments are usually considered to be limited to a single line. In practice however, line comments are often used in series to accommodate multi-line comments. This makes no difference to the compiler as all comments are ignored, but it can make the code clearer for the human reader.
It is worth noting that CodeEnforcer, the automated arbiter of HadronZoo coding standards, will merge line comments into a single multi-line comment block in all cases where the // of the following line comment appears on the very next line and is not preceeded by non-whitespace characters. For example:-
<pre class="codefrag"> uint32_t myVariable ; // Line 1 // Line 2 </pre>
Will result in the description of myVariable being a two line comment namely "Line 1" and "Line 2". This behaviour means that it is safe to write comment blocks using either style. The C-style block comments are more prominent than the C++ style line comments. Comments that describe important entities such as modules, classes and substantive functions, can be line or block comments. Section headers, either within header or source files or within functions, tend to be block comments even though such sectioning has no bearing on program entities!
The coding standards guidelines on comments are entirely aimed at enhancing readability. Consistent indentation is important, within multiple line comments but also among groups of one line comments in close proximity, such as with groups of variable declarations.
Comments should reflect the code hierarchy. For modules there will be a significnt comment block for the module as a whole. For each class (in a module or standalone), there should be a comment block. Functions also get a comment block although the guidelines on this vary. Functions can be overloaded forming natural groups or they can be specifically grouped because they are closely related in other ways. Where functions are grouped attributes of the group can be inhereted. As attributes can be lifted from comments assuming particular formats are adhered to, this wil have a bearing on how functions are commented in the code. Note that trivial functions defined in-line within header files are often not commented.
Multi-line comments should be one of the three styles:-
<pre class="codefrag"> /* // // Comment ** Comment // Comment // more comment */ // // yet more comment </pre>
All single line comments should use the // style. Where these describe declared variables, the comment must be after the declaration and on the same line. In all other cases, these should appear directly above the code to which they apply.
Section 4: Coding Standards for Mainstream Code
The following is both in the interests of code efficiency and clarity and thus error reduction.
Code Indentation
All indentations must be done using tab, which should be set to four characters. Curly braces must appear directly below the start of the condition statement to which they pertain, and NOT on the end! If you are at all dyslexic the latter is utterly unreadable! There are two exceptions to this rule, both involving blocks of short statements that together, fit on a single line, as shown below:-
<pre class="codefrag"> if (condition) { statement1a ; statement1b ; }
or for multiple conditions:-
if (cond1) { statement1a ; statement1b ; } else if (cond2) { statement2a ; statement2b ; } else if (cond3) { statement3a ; statement3b ; } else { statement4a ; statement4b ; } </pre>
Note that multiple 'if - else if - else' type constructs, should have a terminating 'else' and that should if using short compounds statements, use the extra indent.
Parameter Passing
Data structures or classes should be passed by pointer or by reference rather than by value, to avoid unnessesary calls to the copy constructor.
Initialization Variables
Initialization of variables should take place just before the use of the variable and not at the top of the function. This reduces the chance of error. The exception are pointers, which must be initialized to 0 when declared.
Be Const correct
The const keyword should be used wherever the opportunity to use it arises, in order to increase checking by the compiler.
Inline functions
Inline functions should be used where possible for very small routines, to reduce function call overhead. This will be within the class definition body in the header file, or with the inline keyword before the function in the source file.
User Interface Coding Guidelines
The general objective is to localise the user interface code. Wherever possible, the code that deals with the user interface should be self-contained within a class associated with that interface.
Exceptions and exception handling
HadronZoo does not currently use exceptions, either in the library or in programs based on the library, because of the performance cost. Developers are at liberty to use exceptions if they wish to do so, but there are no HadronZoo guidelines on their use.
A Line should not exceed 180 characters
By trying to keep our lines under 180 characters we make our code more readable and thus easier to maintain. This limit used to be 80, then 120, then 160. It has grown with screen resolution and size. The important thing is too make sure code does not wrap in the editor. That looks worse than badly placed curly braces.
Condition Formating
When testing a variable for equality/inequality to a constant, the constant should appear on the left hand side of the == operator, e.g. if (MAX_SIZE == totalSize) {}. This way, if you leave out one of the equal signs by mistake, the statement won't compile and the mistake will be discovered. Note that most HadronZoo code does not follow this guideline, as it was written before the guideline was issued.
Switch formatting
Allowing the execution of a case statement to fall into the next case statement shall be allowed as long as a comment is included. The default case should always be present.
<pre class="codefrag"> Switch ( eErrorType } { case FAILURE : // Fall through - reason this is being allowed case DB_ERROR: break; default: break; } </pre>
Jumps: Continue, Break and Goto
Some coding standard frown upon the use of jump commands, particularly goto. All are allowed under the HadronZoo coding standards. Using goto to break out of several levels of for, while nestings however, is not recommended. Any need to do such a thing may indicate that the inner constructs should be broken out into a separate function.
Short Functions
Functions should ideally be limited to a single page of code. The idea being that each function represents a supposedly simple technique for achieving a single objective. While it is certainly the case that large functions are more prone to error, this guidance can only be taken so far. Logical demarcation must be the overriding concern.
One Statement per Line
In general there should be only one statement per line. However it can make sense to place a block of short statements (enclosed by {}), on a single line, if execution of the block is conditionals and the whole block would fit.
What should go in a Class Constructor?
Constructors should do nothing more than initialize member variables so as to create a blank instance.
What should be included in a Class?
Every class should provide the following: - <blockquote> Default constructor <br/> <br/> | Create/Initialisation routine if one is needed ( In addition to constructor) <br/> | Virtual Destructor <br/> | Dump() and AssertValid() function for debugging purposes. Optional? <br/> | Access functions E.g. Get and Set functions for all private member variables, if needed. <br/> | All code relating to functions should be in one file and all header information in another </blockquote> |
Directory Structure and 'Out of the Box' Operation
New code submitted by code contributors is considered in isolation. Providing it has a clear purpose, works as described, and is written in accordance with the coding standards, it will be accepted. Nobody will ask which directory it was developed in. However when new code is incorporated into the HadronZoo code base, the question of where it should be placed is carefully considered. Although the code base directory structure has no bearing on how the code should be written, it is taken to be a wider adjunct to the coding standards.
The HadronZoo download is a subset of the total code base as not everything is in the public domain. However as the software in the download is 'as used by HadronZoo', the download is an exact subset. The code base directory structure is thus aparent from the download, as follows:-
<pre> ../HadronZoo - HadronZoo root directory ../HadronZoo/data - Miscellaneous data associated with programs, e.g. IP to location tables. ../HadronZoo/code - Root of all source code ../HadronZoo/code/hzlib.{ver} - Root of HadronZoo library ../HadronZoo/code/hzlib.{ver}/doc - HadronZoo library additional documentation ../HadronZoo/code/hzlib.{ver}/inc - HadronZoo library header files ../HadronZoo/code/hzlib.{ver}/src - HadronZoo library source files ../HadronZoo/code/syst - Root of public domain omnipresent server programs ../HadronZoo/code/syst/epistula - Epistula mailserver and webmail ../HadronZoo/code/syst/dissemino - Dissemino Web Engine ../HadronZoo/code/syst/deltasvr - HadronZoo Delta Server ../HadronZoo/code/apps - Root of public domain major command line programs ../HadronZoo/code/apps/codeEnforcer - Code Enforcer program ../HadronZoo/code/util - All public domain major command line programs (currently all in the same dir) </pre>
Note that without exception, programs are dependent on the library, often for the bulk of their functionality. As a result, even the most complex programs have few source files and as a rule, even fewer headers. The standard practice is to place all the program source, together with the makefile and supporting documentation, in the same directory. The oposite approach is taken with the library, which has the documentation, the header files and the source files, in separate directories. The primary reason for the separation, is that only library header files are included in the program code. Another reason is that the library comprises several dozen headers and source files, which would clutter a single directory.
Avoidance of clutter is a strong theme for HadronZoo. In addition to the above directories, the download (and the code base), have a set of directories for object (.o) files. These exactly mirror the source directories as follows:-
<pre> ../HadronZoo/code/.objs - Root of all object (.o) files ../HadronZoo/code/.objs/hzlib.{ver} - HadronZoo library object files ../HadronZoo/code/.objs/syst/epistula - Epistula mailserver and webmail object files ../HadronZoo/code/.objs/syst/dissemino - Dissemino Web Engine object files ../HadronZoo/code/.objs/syst/deltasvr - HadronZoo Delta Server object files ../HadronZoo/code/.objs/apps/codeEnforcer - Code Enforcer program object files </pre>
As old-fashioned as it might seem, the idea is that code should compile in-situ with a make command and that the resultant programs will run 'out of the box' from the command line. Ideally, programs should not depend on other programs although it is understood that this is not always practical. Many HadronZoo programs and Dissemino webapps for example, depend on the delta server for real time backup. As long as every dependency is listed in the README file! What absolutely should be avoided, are complex installation scripts that wander around the machine to discover which version of whatever package may or may not have installed where. Good luck with that!
Version Numbers
Version numbering can easily get out of hand. For independent software the version number regime usually consists of two numbers separated by a period. The first number indicates a major release with which certain key features are associated. The second indicates minor change, often to fix bugs. The version numbers can be prefixed with 'beta' or even 'alpha'. Beta means the vendor thinks it should work, has tested it but not rigorously. Alpha means the vendor intend you to be the lab rat.
Things get more complex when the software has dependencies as there should be some way of indicating the versions of third party components. The HadronZoo recomendation is that in the general case where the third party components are of little interest to the users, this should be noted in a prominent part of the supporting documentation and not in version numbers. A reasonable exception to this is where the software is strongly dependent on and widely associated with, a particular component such as the HadronZoo C++ Class Library. One could have Dissemino_1.2.9.3 meaning Dissemino_1.2 but compiled with version 9.3 of the HadronZoo library. But even here, it is probably better when the library goes to 9.4 or even 10.0, for Dissemino to go to 1.3 regardless of weather or not it has itself undergone incremental change since version 9.3 of the library.