PhAT Coding Conventions


The following page is basically stolen from the Root website (C++ Coding Conventions). I added some comments to it to make it more specific to the PhAT setup.

This document describes the following things:


 


Type and Class Naming conventions

For naming conventions we follow the Taligent rules. Up to now they have written the largest body of C++ and the rules seem well thought out. No need to invent something else. The only addition/change we made is to append an _t to typedefs and simple structs, e.g.:

    typedef int Int_t;
    struct Simple_t { ..... };

Adherence to the rules is mandatory. Any deviation will cause confusion and chaos. After a while one really gets used to the fact that all class fields start with an f followed by a capitalized word, fEnergy, or that TCollection is a class. If the convention is sporadically violated debugging becomes a nightmare. The usage of a standard begin letter or token for the different types also makes it easy to parse and search the code using simple tools.

The following table summarizes the naming conventions:
 

Identifier Convention   Example
Types Begin with a capital letter  Int_t, Float_t, Bool_t
Typedefs/simple structs Append  a   _t typedef int Int_t; struct Simple_t {...};
Data members Begin with a TPhHitArray *fHitArray;
Member functions  Begin with a capital letter Draw(), FindVertex()
Local variables and function parameters Lower case words TPhHit hit, Int_t moreData
Globals / Static variables Begin with a g TPhDetector *gDetector;
Static data members Begin with fg TPhDetector::fgIsInitialized;
Constants(including enums) Begin with a k const Bool_t kTRUE = 1;
Enumeration types  Begin with a E enum ERunMode { kSetupFEC, kCalibration };
PhAT classes  Begin with TPh TPhHit *hit;
Acronyms  All uppercase TPhMul,  TPhVTXSensor
Getters and Setters Get...() and Set...() GetNextEvent(), SetMagnet()
Members returning a Bool_t Is...() IsOn()

Class definition conventions

Also here the Taligent guide is quite reasonable. Of course, no class data member should ever be public (OO remember). Make the data fields always private. Or protected, if you want to grant an inherited class direct access. Concerning inlines. Add trivial get or setters directly in the class definition (improves reading time since one does not have to look for it somewhere else). Add more complex inlines (longer than one line) at the bottom of the .h file. Creating separate .icc files increase the build time, the complexity of the Makefile and, more importantly, increases the number of files one possibly has to scan to find a piece of code (remember code is write once, read often).

Avoid raw C types

Avoid the use of raw C types like int, long, float, double when using data that might be written to disk. For example, the sizes of int and long are machine dependent. On an old PC an int is 16 bits and a long is 32 bits. On 32 bit workstations int's are 32 bits, but on 64 bit processors an int can be either 32 or 64 bits, depending on the processor. For portability reasons and consistent numerical results use typedefs for the basic raw C types.

Indexing Arrays in PhAT

We use the C/C++ convention to index arrays in PhAT. That is all indices run from 0 to n-1.

Class Versioning

In the class header file, you will need to include a ClassDef(TPhMyClass,1) statement. This is a  ROOT macro that is needed to have ROOT insert appropriate code and to tell ROOT what the class version of the class is (in this case 1). The class version is important when reading and writing an object to a ROOT file, because it gives a method of distinguishing the memory layout of a class as the classes evolve. Every time you change any of the data members (add, delete or change the order in the header file or change the inheritance tree), you must increase the class version. If the class that you are dealing with is one of the detector or data classes, then it is especially important that you provide or edit the Streamer function to take care of the new class version and either provide backward compatibility or at least a statement that the class with lower version number is no longer supported. It is very difficult to maintain backward compatibility when the inheritance tree is changed, a message warning the user is probably the only thing that can be done. Have a look at TPhSensor::Streamer() to see how  the class versioning can be implemented. There are basically two cases: the class already has a Streamer function in the source code or it does not have one and you need to provide one.

Class has a Streamer function in the class source

If the class already has a Streamer function in the class source (the .cxx file), then you need to do the following steps:

  1. Change the data members of the class
  2. Increase the class version in ClassDef in the header file
  3. Run 'rootcint [your  class.h]', this will generate a bunch of code on your screen.
  4. Copy&Paste the read section of the Streamer function (everything in-between the 'if(R__v){}' and '} else {' statements) into the Streamer function in the source code. Make sure that you change the 'if(R__v){}' into
    'else if(R__v == newClassVersion)'. 
  5. Now Copy&Paste the write section of the generated Streamer function into the source, deleting the write section of the old class version.

Class does not have a Streamer function

If the class does not yet have a Streamer function in the class source (the .cxx file), then you need to provide one. For this you do the following:

  1. Before doing any changes, run 'rootcint [your  class.h]', which will generate code automatically.
  2. Copy&Paste the whole Streamer function that you just generated into your source code.
  3. Change create_cint , by appending a '-' to the #pragma statement, e.g.
        #pragma link C++ class TPhSensor-;
    This will ensure that rootcint does not generate a Streamer function automatically.
  4. Follow the directions given in Class has a Streamer function in the class source

Note that you do not have to declare the Streamer function in the header file explicitly. This is done behind your back in the ClassDef macro.

Using comments to document the code

Using the information stored in the dictionary and the source files ROOT can automatically generate a hyperized version of the header and source files. By placing comments in a few strategic places a complete reference manual, including graphics, can be generated using the THtml class.

There are three different kind of comments used by THtml.

Data member description comments

Comments behind a data member definition in the header file, e.g.:

Float_t     fEnergy;     // the particle energy

The comment "the particle energy" will be put in the dictionary and used whenever fEnergy needs to be described (e.g. on-line help). Have a look at a raw header file and compare it to the hyperized version.
 

Class description comments

A comment block at the top of the source file describing the class. It follows immediately behind the ClassImp statement and will be included in the HTML for the class. It should also have a delimiting string, in PhAT this consists of a long row of '///////', e.g.:

ClassImp(TPhDetector)
////////////////////////////////////////////////////////////////////
//                                                                //
// The TPhDetector class provides an interface to the PHOBOS      //
// geometry. It is currently filled by the TPhASCIIData and       //
// TPhPMC classes, which are interface to the Geant MC, PMC       //


For an example of a class description comment block see this source file and compare it to the hyperized version.

 

Member function description comments

The first comment lines after the opening bracket ({) of a member function are considered a description of the function. For example:

TList::Insert()
{
   // Insert node into linked list.
   // To insert node at end of list use Add().
   ...
   ...
}

Here the two comment lines after the { are used to describe the working and usage of the member function. For a real life example see this source file and compare it to the hyperized version.

 

CVS related comments

Since we use CVS as our code management tool, we also want to have some documentation of what the revision number of a file is. In order to get a consistent look we use the following convention: at the very bottom of the class description, add:
 

//
// $Id$
//

The $Id$ will be expanded by CVS to include the last revision number, date and the name of the author who revised that file. It should look something like this when committed to the Repository:

//
// $Id: TPhDetector.cxx,v 1.12 1998/09/22 16:10:43 decowski Exp $
//

CVS will automatically update it every time you revise the file. Remember to stick this in for both the class source file and the header file.

HTML directly in the source

In the class and member function description comments one can also insert "raw" HTML. This gives the possibility to have nicely formatted text or, more importantly, to be able to include graphics into the source showing, for example, a data structure, an algorithm an inheritance tree, etc. For example:

TList::Insert()
{
   // Insert node into linked list.
   // To insert node at end of list use Add().
   //Begin_Html
   /*
   <img src="gif/list.gif">
   */
   //End_Html
   ...
   ...
}

Everything enclosed by the //Begin_Html and //End_Html lines is considered to be pure HTML (to not confuse the C++ compiler the HTML block has to be enclosed by C style (/* ... */) comments.

Code Appearance

There is no enforced C coding style, be it K&R, GNU C or Strastroup. The only requirement is that the code is legible (e.g. whitespaces where appropriate) and it is good to be consistent in the notation. However, make lines  less than 80 characters in length. If the line is longer, then please add a new-line before hitting the last column. If you need to break a string then you can do it in the following manner:

0---|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----79 
    Warning("MakeHitArraysOutOfHits", 
      "%s data container already present in the event - "\ <- Note '\'
      "choose another name\n", HitArrayConName);
  
  

Where to go from here

For the rest read the Taligent Guide and use common sense.