1. Style Guide
    1. In General
      1. Indentation and Line Width
      2. Other whitespace rules
      3. Comments
      4. Those damned curly braces
      5. Naming Conventions
    2. C++ Code
      1. Namespaces
      2. Reference Counting
      3. Other Points
    3. Crack Code
      1. Special Naming Conventions

Style Guide

This is the coding style guide for the crack project. If you are submitting code for this project, please follow these guidelines.

Describing coding style is complicated. While this guide attempts to enumerate all of the rules, it will inevitably let some of them slip through the cracks. Remember that the point of this is to produce a codebase with a uniform appearance. If this guide doesn't identify some practice as a rule, it doesn't mean that it's ok. Please try to code in a manner consistent with the examples here, and with the body of the code if there are no examples.

In General

These rules apply to both C++ and Crack code.

Indentation and Line Width

Lines of source code should not exceed 80 characters.

Use 4-character indents. Exceptions to this rule:

Note that you should only use this alignment for statements that don't fit into 80 characters. Whenever possible, write one statement per line.

There are alternate formatting rules that apply in special situations:

Other whitespace rules

When creating a new file, be sure that the file doesn't introduce trailing whitespace (whitespace at the end of a line after non-whitespace characters). For existing files that contain trailing whitespace, preserve it.

Use a single space:

Do not use spaces:

Comments

Comment code liberally. Comments should be used to provide a terse description of sections of code, a clarification of complicated algorithms, and descriptions of cases where unusual code needs to be written. Use one blank line before a commented section of code:

    # move the contents of foo to bar:
    TreeMap bar = {};
    for (item :in foo)
        bar[item.key] = item;

    # remove all instances in the collection from the superset of all elements.
    for (item :in bar)
        superset.delete(item.key);

For comments that apply to multiple following sections of code, follow that comment block with a line:

    # read the contents of the configuration file and convert it to a tree.

    # parse the config file
    while (tok := configToker.getToken())
        parser.inject(tok);

    # convert to a datastructure
    TreeMap config = {};
    for (elem :in parser.getAllElements())
        config[elem.name] = elem.value;

Use "XXX" comments to indicate places where functionality is incomplete or intentionally broken.

    # remove all instances in the collection from the superset of all elements.
    # XXX should be performing a complicated algorithm to determine set
    # membership instead of just relying on the name.
    for (item :in bar)
        superset.delete(item.key);

Provide doc-comments for all public functions and interfaces. These may be omitted for methods that simply implement documented base class methods:

    ## Represents a really cool object.
    class CoolObject : RighteousObject {

        ## This method does something awesome.
        ## desc: description of the thing to do.
        void doSomethingAwesome(String desc) {}

        void implementedBaseClassMethod() {}

        void __undocumentedPrivateMethod() {}
    }

It is acceptable to provide doc-strings for private methods, but not necessary.

Those damned curly braces

Place the beginning curly brace at the end of the originating statement, align the end curly brace with the beginning of the originating statement:

    void function(Type arg) {
        while (condition) {
            statement;
        }
    }

The exception to this rule is function or class definitions that are relatively simple and fit on a single line:

    class Foo { int a, b; }
    void square(float f) { return f * f; }

Put a single space between the end of the statement and the opening curly brace, as in the examples.

For an "if/else" statement, use "cuddled" elses:

    if (condition) {
        statement1;
    } else if (other_condition) {
        statement2;
    } else {
        statement3;
    }

For all statements where curly braces are optional, use curly braces unless the contents are a single-expression statement.

    while (condition)                       // OK
        doSomething(firstArgument,
                    secondArgument
                    );

    while (condition)                       // WRONG!
        if (otherCondition)
            doSomething();

    while (condition) {                     // OK
        if (otherCondition)
            doSomething();
    }

If any part of an if/else needs to be in curly braces, all parts of the if/else should be in curly braces:

    if (condition)                          // WRONG!
        statement1;
    else if (otherCond)
        statement2;
    else {
        statement3;
        statement4;
    }

    if (condition) {                        // OK
        statement1;
    } else if (otherCond) {
        statement2;
    } else {
        statement3;
        statement4;
    }

Try/catch statements should also use cuddled exception clauses:

    try {
        statement;
    } catch (Exception ex) {
        handler;
    }

In a block that is not part of a statement, align the curly braces with the contents of the enclosing block and indent the contents normally:

    doSomething();

    {
        Type scopedVariable;

        scopedVariable.doSomethingElse();
    }

Naming Conventions

Type names should be camel-case, first character uppercase:

    class ClassName { }

Variable, method, function names should be camel-case, first character lower-case:

    void doSomething() {
        int someValue;
    }

Namespace and module names should be all lower-case, separate by underscores:

    sample_name

C++ Code

Namespaces

Identifying namespaces in header files should be as unobtrusive as possible: they should not require indentation of the contents or multiple lines for nested namespaces. When defining a nested namespace, put all namespace statements on the same line, and put the closing brackets on the same line followed by a comment:


    namespace builder { namespace mvll {

    // note that class is not indented.
    class Foo {
        // contents...
    };

    }} // namespace builder::mvll

Reference Counting

Classes that are dynamically allocated use reference counting. These are classes derived from spug::RCBase and have pointer templates with the suffix "Ptr" (defined by SPUG_RCPTR(ClassName)). For Reference counted classes, use either reference counted pointers or raw pointers depending on the circumstances:

Other Points

Use '//' style comments for everything except doxygen comments, use /** */ for those:

    /** Single line docstring. */
    void doSomethingSimple();

    /**
     * This method is so complicated that it requires
     * a multi-line docstring!
     * @param arg this is a docstring.
     */
    void doSomethingComplicated(String arg);

Crack Code

Special Naming Conventions

Per language requirements, private class members shouold begin with a double-underscore:

    class A {
        int __a;
        void __f() {}
        class __PrivateNested {}
    }

Module-private/protected variables, functions, methods and classes should begin with a single underscore:

    class _A {}
    void _f() {}

    int _moduleVar;