GLAST Ground Software Standards: A Start

Naming StyleCoding rules

The “recommendations” in this document are in some cases specific and concrete; in other cases they are just suggestions for the form an actual recommendation should take. I've used the CERN document C++ Coding Standard, Version 1.1 as a starting point. This document covers three major areas: naming, coding and style. All three are important and the document has useful things to say about them all, but for our purposes naming is most urgent and probably can be addressed with a few simple rules. I will distinguish between items which I consider to be requirements and those which are merely recommendations. There are only a small number of the former, but, as a consequence, some of the recommendations will be very strongly recommended.

Following good C++ coding practices is of course also vital, but a much more complex issue. I can't do better than to refer to [1] , and [2]. A few of the recommendations in the CERN document, with comments and amendments, have been reiterated below. There are plenty of other items in that document which are just as important in an absolute sense, but they either are less relevant to our code or are rules which are mostly followed (to my knowledge) in GLAST code.

Naming

Naming conventions are needed for at least two reasons: to avoid collisions and to aid the human reader in making sense of the code. The more global the name, the more pressing these concerns are.

  1. Namespace use
    In code we own and maintain, each package containing publicly accessible classes (other than pure interface classes) must use a namespace name identical to the package name for those classes. In this way we avoid inter-package collisions. Namespace use is optional in other situations, but if used, the namespace name must still be identical to the package name.
  2. Using directive and public header files
    Using directives must not appear in public header files.
  3. Using
    More generally, use using with care; too many using directives and declarations or those with broad scope will undo the benefits of namespaces. Most uses of using should have only function scope. Consider using an alias rather than a broadly-scoped using directive to avoid typing a long namespace name repeatedly.
  4. Package name choice
    The initial word is capitalized for (locally written) Gaudi-using packages, lowercase otherwise. Subsequent words are always capitalized.
     
        PackageUsingGaudi
        gaudiFree
    
    Note: some existing packages violate this rule. Nonetheless, it should be followed for new packages.
  5. Files and classes
    A single header file will describe only a single public class or tightly-coupled classes (e.g., an inner class and the class containing it when the inner class is unlikely to appear independently in client code) and similarly for implementation files.
  6. File names
    All header files will use the suffix .h and will be named after the class (most prominent class, if more than one is declared in the file) being described. Except for the suffix, the same goes for implementation files. All new implementation files (other than perhaps implementation files consisting solely of inline function implementations) will use the suffix .cxx.
  7. Old files
    Filenames of existing locally-written files not in conformance with the above recommendation will be adjusted as time permits. Imported software may use a different convention, e.g. suffix .cpp for implementation files.
  8. Tag names
    We need a convention for tag names. The format should include a place for three numbers (major release number, minor release number, patch number) and some string to indicate the scope of the tag. For individual packages tag names should follow the CMT format where the three numbers are prefaced by v, r and p (for version, revision and patch), e.g. v1r5p1.
  9. Descriptive names
    Names should be descriptive (and of course accurate!); use abbreviations only when already well-known.
  10. No duplicates
    New names should not be confusingly similar to existing names, especially existing names within the same scope. For example, don't use the same word for a namespace name and a classname and don't choose variable names which differ from each other only by capitalization. However the convention of naming a variable after the class name, but with initial lowercase, is acceptable:
    Track* track;
  11. Detailed standards
    Adopt detailed recommendations on capitalization, prefixes, etc. for class names, method names, etc. Here is a proposal, largely taken from [1], along with the sentiment that consistent compliance with such a standard is more important than the details of the standard chosen.
    1. Classnames consist of one or more "words," each of which is capitalized. The remainder of each "word" is lowercase, even if it is an acronym.
    2. typedefs and enum types begin with a capital letter.
    3. Function members (except for constructors and destructors) begin with a lowercase letter.
    4. Data members (non-static) begin with m_ followed by a lowercase letter. For static data members, the prefix s_ may be used.
    5. Local variables begin with a lowercase letter.
    6. In names consisting of more than one word, one of the following conventions should be used consistently within the file the second and subsequent words are always capitalized.

Here is a code example demonstrating most of these recommendations:

   class MyClass       
   {
     public:
       MyClass();

       int   myMemberFunction();
       enum  Colors {red, green, blue}; 

     private:
       int        m_myDataMember;
       static int s_staticMember;
   };

Style

Paraphrasing slightly from the CERN document, we can say style concerns that which is apparent to the human reader, but does not affect compilation. What constitutes good style, at least in detail, is certainly something about which knowledgeable people can disagree; however #1 below is required for readability in our cross-platform environment while #2 and #3 are highly desirable.

  1. Tabs and indentation
    Tabs should not be used in code. Achieve indentation by using explicit spaces. This is the only way to ensure that code indentation is rendered properly for everyone on the screen and when printed.
  2. Consistency
    At least within a file, but preferably within a package, be consistent in indentation style, capitalization rules for names, etc.
  3. Line width
    Lines should normally be no wider than 80 characters, but in circumstances where this doesn't suffice (e.g., long literal strings), keep it to 132.
  4. White space
    Use white space in preference to divider lines like
    /////////////////////////////////////////////////////////////////////
    to set off blocks of code or comments. As you can see, such a divider line without any additional space isn't very effective.

Coding

Format in this section is

Paraphrase of text from CERN document (subsection, rule id) Additional comments.

  1. Numeric constants
    Numeric constants (other than small integers in certain situations) should not appear in executable code. (3.3.1, CL3) Declare as (usually static const) variables with meaningful names instead.
  2. Variable scope
    Declare variables with smallest possible scope and usually [my modifier] initialize at the same time. (3.3.1, CL2)
  3. Use of #define

    All header files need #ifdef..#define..#endif protection to avoid multiple inclusion. All other uses of #define are strongly discouraged; there are generally better alternatives in C++. (3.11, CA4, CA5) Rather than defining function-like macros, use inline functions. Instead of using #define for symbolic constants, define a const variable or use enum.

  4. Complicated methods
    Do not have overly complex functions (3.2, CF6) There is rarely a good reason for a function to exceed what is readily visible on the screen, about 40-50 lines of no more than 80 characters.  Most functions should be quite a bit smaller.
  5. Check inputs
    Pre-conditions and post-conditions should be checked for validity  (3.9, CE1) Verify that any input which can produce an exception or invalid output (e.g., number whose square root will be taken) is within the proper range or has the proper form. The only exception is that an argument being passed among internal methods need only be checked once.
  6. Error handling
    Check for all errors reported from functions; when reporting errors use exception handling rather than status codes as appropriate  (3.10, CH1,2,3) There is nothing more to say about the first part other than to repeat it for emphais: check for all errors reported from functions.   As for reporting errors, since exceptions are a new programming feature to many, there is a tendency to use status codes when throwing an exception would be a better way to report the error. However, there are times when a status code is the better choice, for example if you are reporting an unwelcome, but not abnormal, condition.
  7. Duplicated code
    Avoid duplicated code. (3.12, CR1) Factor out common functionality into a single method. This is a constant process as code evolves, not just something to think about when the code is first written.
  8.  Optimization
    Optimize code only when you know you have a performance problem (3.12, CR2) In particular, code with many nested function calls is difficult to read and can be difficult to step through in a debugger. Any decent compiler, even if unoptimized, will tend to keep short-lived intermediate local variables in registers, so there is rarely any performance advantage to the nesting.
  9. Copying objects
    Avoid unnecessary copying of objects that are costly to copy. (3.3.3, CL8)  See also related points about argument passing, especially 3.5.2, C14 (Pass arguments of class types by reference or pointer.)
  10. Inlining
    Use inlining with care.  In general, inline only very simple functions.(3.5.1, C11) There are times when the performance improvement of inlining something more complex is worth it, but they're rare.

References

1. C++ Coding Standard, Version 1.1, Project Support Team -IT Division, CERN, 5 January 2000.

2. B. Stroustrup, The C++ Programming Language, special edition, Addison-Wesley, ISBN 0-20170073-5.

Joanne Bogart

7 August 2000
20 September 2000 Rev. 1
Last modified: 06 April, 2004 10:47:08 -0700