A Coding Style

    This document describes one particular coding style, mainly from the perspective of indentation, spacing and alignment.  So, it is more of a manual of typography than of style, I suppose.  It is not intended to indicate anything wrong with other styles, or anything particularly right about this one.  It is instead intended to bring out the potential of a coding style for regularizing and beautifying code.  I have found this to be true in my own work and to really stand out when I read the code of others who follow no particular style; their code bites my eyeballs.

Identifiers:

    Objects and variables should be declared one per line.

    Multiple word variables names should have the words separated by underscores.

    Type modification syntax (* or &) should be kept with the variable name that it modifies.  For example:

    int *fred
    point &gen
    Variables should always be named in a manner that makes their purpose clear.  The only exception to this is that simple loop variables can have single letter variable names.

    Do not use abbreviations within variable names unless the abbreviations are standard within the field the program is targeted for.  Num_spn_pt means nothing to anyone besides the original programmer, and usually means nothing to that person after a few months of not seeing the program.

    Variables used exclusively for boolean conditions should be named such that the expression reads like a sentence:

    if (level_is_too_high) ...
is fine, but
    if (exponent_q) ...
does not seem as clear.

Constants:

    Instead of using #define to create symbolic constants, use const or enum.

    Enums are used when a group of constants are associated with each other, as in a set of possible outcomes from one operation.

    Use all capitals to make global constants stand out.  However, do not use global constants; put them in a namespace instead.  Within a namespace, sometimes capitalized names help and sometimes they don't.  Use your judgement.

Comments:

    Comments are necessary for explaining the purpose of a function or of a code fragment.  Every function in an header file must be documented with a comment.  Every odd algorithm should be systematically commented.  Even small functions often need comments to explain how they operate.  Commenting is a good thing.

    Comments can be misused however.  They are not executable in any case; this just means that an informal comment will never be used as part of the program, and so the comment cannot impose any rules on program behavior.  Unfortunately, a comment CAN make the user think the software acts a certain way when it does not, and hence the comment has served a purpose contrary to clear documentation.  Therefore it is extremely important that comments are clear and that they are kept up to date.  Periodic code reviews are useful to help ensure this.

    Show your code to others.  If they cannot interpret the comments, the comments need more work.

    Either the `//' of C++ or the `/* ... */' of C can be used, but comments must not be nested if both are used arbitrarily.  If only the `//' is used for comments and the `/* ... */' is only used for commenting out sections of code, then nested comments does not cause conflicts.

    Header files (.h) are where the purpose of a function should be specified, not the implementation (.cpp) files.  The implementation files should however contain any extra information regarding how an algorithm works or where changes in implementation might be made in the future, not the header file.

    Comments can either precede the piece of program being commented, in which case they should align with that code, or they can follow a piece of code, in which case they should be indented and they should follow the code without line breaks.

    Comments for function prototypes that come before the function should include the name of the function and be stated in terms of a complete sentence.  The name can be used as an implicit subject beginning the sentence:

    // cycle_washer: begins adding water to the tank and churning the clothing.
    void cycle_washer(long milliseconds_to_cycle);
Comments that come after the prototype should follow the same format except that the function name may be omitted (because it is right before the comment).  For example:
    void cycle_washer(long milliseconds_to_cycle);
      // begins adding water to the tank and churning the clothing.

Indentation:

    It is necessary to indent blocks of code inward as the depth of nesting increases.  This not only serves to clarify the logical sections of the code, but is also helpful in showing program structure.  If nesting is so deep that the indentation is more than about halfway into the page, then the algorithm is probably programmed in too complex of a manner.

    The number of spaces for indentation of each block should be 2, and should be consistently used wherever indentation is found.  1 space is nearly invisible, and 3 causes the indentation to move to the right at a higher rate than 2.

Spacing:

    Spaces are never used before a semicolon, but can be used after one (as in a for-loop).

    Spaces, not tabs, are used for indentation.

    Spaces are never used before a comma, but are always used after a comma (unless the end of line is after the comma).

    Spaces must separate operators from operands.  For example, x+1 is reasonable, but x + 1 is more readable.  (x+2*y-30*z+sin(23*l)) is gibberish, while (x + 2 * y - 30 * z * sin(23 * l)) is more readable, and (x + (2 * y) - (30 * z * sin(23 * l)) ) might be even more readable.  Note that spaces are not required between a parenthesis and another character, but they should be used between a multiple nested parentheses in a manner that is consistent with the expression.  The spacing in this case can help bring out the structure of the expression and make it more readable.

Blank Lines:

    One vertical space (a carriage return used as a blank line) should be used to separate distinct pieces of the program from each other.  Blank lines are not needed between statements that are very similar in character, such as the definition of constructors or operators in a class definition.  Blank lines can also be used to separate distinct algorithmic phases or distinct sections of source code from each other.  The overarching concern is making the program more readable; use a blank line where it assists this.

Brackets:

    An ending bracket for a block should line up with the first character that is at the beginning of the block:
    while (...) {
      ....
    }
For multiple block statements, the brackets should line up at every level in a similar manner:
    if (...) {
      ...
    } else if (...) {
      ...
    } else {
      ...
    }
    Switch statements are a special case...  Each case that constructs an object on the stack is required to have brackets around it when objects are being constructed inside that case.  Every case MUST have a control-flow-redirecting statement at the end of the case, such as break, return, or continue.  Don't forget the default case in a switch statement that has not considered all cases.  Also, fall throughs between cases are allowed as long as they are documented.

For example:

    switch (to_switch_on) {
      case C1: {
        int numb;  // brackets needed because of local variable.
        ...
        break;
      }
      case C2:  // intentional fall-through to case C3.
      case C3:
        ...
        return to_return;
      default:
        ...
        break;
    }

Statements vs. Function Calls:

    Statements do not need to use parentheses around arguments, and should not.  Function calls are already required to use parentheses by the compiler.  The statements new, return, and delete in particular should not be surrounded with parentheses.  This is not to say that parentheses should not be used to make expressions more clear.  For example, the first expression below could also be written: return (x * y) - 3;.

                 "RIGHT"                                  "WRONG"

    return x * y - 3;       return (x * y - 3);

    new fred_class(23);     new (fred_class(23));

Header files (.h files):

    Do not use function prototypes that omit the variable names for parameters.  This can make the purpose of those parameters difficult
to figure out, and then requires documentation where an appropriately named parameter would have sufficed.

    Always surround a header file with a guarding set of macros:

    #ifndef BLORG_HEADER
    #define BLORG_HEADER
    // .... header file contents ....
    #endif
This keeps a header file from being represented more than once when it has already been included in a program.  In some cases, such as
definitions of variables in a header file, the multiple inclusion of a header file can cause problems.  Note that the last word above is variable depending on what is defined in the header file; if the header file defines a class, then the word should be _CLASS.  In almost all other cases, the last word should be _HEADER or _SUPPORT or a similar "grouping" keyword.  This is just to provide a bit of redundant documentation in the #ifndef syntax.

    Keep a header file to one abstraction per file.  There is a tendency to group similar but different class definitions in the same header file.  However, when multiple classes are contained within the same header file, clarity can suffer and the abstracted concepts can become mixed together.

    The header file should be named appropriately.  If it defines a strings class, then the header file should be named strings.h.  If it defines a balanced tree abstraction, then it should be called balanced_tree.h.  On primitive systems that do not allow long names, this becomes a fairly obnoxious art form (like bal_tree.h instead).

    Blank lines are used in header files to separate functions from each other when they are for distinct purposes.  Functions that are very similar can be grouped together without any extra spacing.
 
    Do not include header files in other header files unless part of their interface is promoted, possibly through class derivation or because definitions from the included header file are needed.  Practice forward declaring objects by prototypes to help cut down on the number of inclusions needed in your own header files.  For example:

    class planet;  // forward.
    class planet_user {
      planet_user(planet &to_use);
    };
is a lot more efficient than:
    #include "planet.h"
    class planet_user {
      planet_user(planet &to_use);
    };
because it doesn't include that extra file.  However, sometimes including headers is unavoidable; don't shirk it then.

Class definitions:

    The members of a class are indented, but access modifiers (public, private, protected) are not indented.

    The public members of a class should come first, since casual perusal of the class by a user will have the most benefit if those members that are intended to be used are seen before the protected and private members.  Protected members come next, and then private members.

    The constructors are listed first in a class definition, and are followed by the destructor.  This order should be used in the implementation file also.  (If a non-member function is invoked by the constructor, then there must be a prototype for the non-member function before the constructor, rather than the non-member function being placed there itself.)

    class bean_counter
    {
    public:
      bean_counter();
      ~bean_counter();
      int how_many_beans();
    private:
      int current_bean_count;
    };

Function prototypes & implementations:

    Use void as the return type when a function does not return a value.
    void no_return_value(int peanuts);
    In C++, use emptiness as the parameter type when a function has no parameters.  For example:
    int no_parms();
In C however, it is a good idea to use the keyword void instead because simply having no parameters listed in a prototype does not imply that the function actually takes no parameters.  For example:
    int no_parms(void);
    Indent two spaces from the prototype for the function body.

    Put the beginning bracket of the function on a separate line from the prototype.

    void stuff_array(int to_stuff)
    {
      body goes here.
    }
    For functions with long lists of parameters, the parameter list can be broken up, indented twice as much as normal and continued on succeeding lines.  Splitting the list at the first parenthesis is okay.
    int function_with_long_parameter_list(int a, int b, int c, long q,
        cauliflower_set this_one_got_moved_down, int turnip_power,
        void *to_shoot, rectangle frame_of_reference)
    {
    }

    really_long_return_type my_function_with_a_long_name
        (int handle, actuator_list controls)
    {
    }

Implementation files (.cpp files):

    Use the .cpp ending for implementation files.

    Do not include header files in code files unless they are really needed.  If a header file B.h is based on a header file A.h by including it, and you are already including B.h, then do not also include A.h.

Standard in & standard out:

    Use the cin and cout objects (defined in streams.h) as the means of printing information to standard in and standard out.  Scanf & printf were used in C, but have been replaced by the use of cin with >> and cout with <<.  The double bracket operator stuffs a value into the object it points at, where these values can be the standard integers, doubles, etc.

Line wrapping:

    If a program statement is too long for one line, then it should be broken up in a natural way.  The multiple lines should still seem to
be one logical line.  Breaking the line up at operators is recommended.  For example:
    size_of_messages = number_of_messages
        * (number_of_packets * size_of_packets + header)
        + message_overhead;
    When parenthesized items need to be broken up, add extra indentation to make it obvious that the continued part of the line is inside the
parentheses.