Coding Standards

From Sirikata Wiki
Revision as of 01:07, 24 July 2009 by Danielrh (talk | contribs)
Jump to navigation Jump to search

In general, follow the Ogre coding style. If some code requires formatting not covered by this page, please add the appropriate guidelines for such code to this list.

  • Adhere to the ISO C++ standard. If you must put in non-standard

workarounds for specific compilers, document this and make sure the code compiles as expected on a standards-compliant compiler as well.

  • Indent with four spaces: no tabs. (Note that this is different

from Ogre.)

  • Use Unix linebreaks (LF).
  • End each file with a newline, and remove all trailing whitespace

from individual lines.

  • Endeavor to be const correct everywhere: modern

compilers can use this to a huge advantage.

  • Opening braces are always on the same line as the keyword, except

for class and function definitions.

namespace MyNamespace {

class MyClass {};

MyClass::MyClass(int val1, int val2)
: mVar1(val1), mVar2(val2)
{
    if(a) {
        myFunctionOne();
        myFunctionTwo();
    }else {
        myFunctionThree();        
    }
}

}  // namespace MyNamespace
  • Functions definitions that are sufficiently short to inline should

be defined in the with the class declaration (usually in the .hpp) and live entirely on one line:

class MyClass
{
    MyClass::myFunctionOne() { return 1; }
}
  • All names are in camel notation, e.g. MyClass,

MyNamespace, myFunction, mMemberVariable and should be maximally descriptive. That is, a function that computes the length of something should be called myLength() instead of Len(), and a loop that iterates over a list of Spimes should look like for (int spime = 0 ; spime < spimeLength; spime++) instead of for (int i = 0; i < spimeLength; i++).

  • All function names start with a lower-case letter.
  • Member variables start with the lowercase letter 'm'.
  • Stick to 155-character screen widths as far as possible.
  • Write the minimum amount of code that does what you need to

do. This means that

if (condition) value = myFunction() + 1. / 3 * 5;

is much preferable to

if (condition == true) {
    value = (this->myFunction() + (1.0 / 3.0) * 5.0));
}

In the vast majority of cases, if the compiler doesn't need parentheses or brackets, you don't need them either.

  • Use whitespace where appropriate. In particular, clearly separate

successive blocks, function declarations etc (a good model is the MyClass code to illustrate indentation below). Also, put spaces in mathematical expressions, e.g. x = a + b + c;, not x=a+b+c;, and after delimiters in general, especially commas (e.g. int a, b;, not int a,b;).

  • In general, you should put comments wherever you feel that they

enhance the readability of the code. However, if you're writing good code, there should be very few instances where this is the case. Redundant comments (like the one below) are pernicious and should be avoided:

if (programOptions[OPTION_MODE] == "server") { // server
  • Doxygen comments should be written like this:
/** Short description of function foo.
 *  Longer description of function foo that may span many lines
 *  like this blah blah blah...  Return type should be on same line
 *  as start of function name to support eventDispatch lookups
 */
void foo()
{
    ...
}
  • Non-Doxygen comments should be written like this:
// Let x be the sum of a and b.
x = a + b;

// Now loop over values of i from 0 to 9, adding
// 1 to x at each stage.
for (int i = 0; i < 10; ++i)
    ++x;  // Faster than x = x + 1?
  • Function definitions should always be preceded by a comment of the

following form:

//#####################################################################
// myFunction
//#####################################################################
void myFunction()
{
    ...
}
  • A namespace declaration does not induce a level of indentation.
  • Indent within a class as follows:
class MyClass
{

  public:

    /** Short description of foo.
     *  Long description of foo.
     */
    void foo();

    /** smallFoo has only a short description. */
    void smallFoo();


  private:

    /** Short description of bar.
     *  Long description of bar.
     */
    void bar();

};  // class MyClass
  • When defining a function (except when it is inlined within a class

declaration), put its name and return type on a separate line, indented as little as possible. That is:

[template <class T>] [inline]
void MyClass::foo(int n)
{
    ...
}
  • Initialization lists are written like this:
MyClass::MyClass(std::string const & name, int age, int uuid)
: ParentClass(uuid), mName(name), mAge(age)
{
    ...
}
  • Write typenames so they can be read right-to-left, e.g.

std::string const & name can be read as: "name is a reference (&) to an immutable (const) string", and int * const p can be read as: "p is an immutable (const) pointer (*) to an integer". Note that in the latter case, the integer can be changed through p, but p cannot be reseated to point to something else, which is made clear by the right-to-left reading.

  • When a function has so many arguments that it cannot fit in 155

columns, write its declaration like this:

void foo(int a, int b, int c, int d, int e,
         int f, int g, int h, int i, int j);

... and its definition like this:

void foo(int a, int b, int c, int d, int e,
         int f, int g, int h, int i, int j)
{
    ...
}
  • Use "get" and "set" as prefixes to accessor and modifier functions.

i.e. use int getAge() and void setAge(int age), not int age() and void age(int a).

  • Prefer clear, well written code that reads naturally to

documentation. Document all functions for Doxygen and reference purposes, but within functions or for private functions, document only as necessary. However, don't under-document code. Prefer over-documentation if you are unsure if documentation is necessary.

  • Prefer references to smart pointers, and smart pointers to raw pointers.
  • All text (comments, identifiers etc) should be in English except for

technical terms for which it's conventional to use another language. For consistency, prefer the American spelling for identifiers.

  • Don't write if (a) delete a;. delete may

safely be called on NULL.

Logging

  • All debugging printouts should use our new threadsafe logging

mechanism which is customizable on a per-user basis through config files and/or command line options.

  • The Logging.hpp contains macros that should be used to construct the

output stream to write logs to.

  • Prefer your subsystem macro:
  • If you are working on graphics and you wish to write a log that will

be seen by default write

     MERU_LOG_OGRE << "Everyone will see this"
  • If you are working on graphics and wish to write a log that will

assist you in debugging and should only be seen by others working on the graphics subsystem do

     MERU_L_OGRE(debug) << "Only Ogre graphics developers will see
this in the meru system"
  • If you are working on graphics and need to spam the console with

information to get at a bug use

     MERU_L_OGRE(insane_debug) <<"This is only for the folks willing
to sacrifice serious performance to view logs"
  • subsystems include MERU_L_OGRE, MERU_L_CDN, MERU_L_EVENT feel free

to add others where necessary by following the same path of coding as the other 3 subsystem logs

  • If your log message is generic to overall Meru and does not belong

in a category (eg: ready to serve users) use the MERU_LOG(<level>) where level can be one of [insane_debug,debug,info,warning,error,fatal] Here's an example

MERU_LOG(debug) << "Class Hierarchy Ready, go to loading phase";
MERU_LOG(info) << "Server ready to accept clients";
MERU_LOG(warning) << "Value of ProxyObject should not be null";
MERU_LOG(error) << "Empty config file. Wrong path? "<< mypath;
MERU_LOG(fatal) << "Cannot recover from "<<err<<" aborting";
  • There are macros for each of these debug levels
  • Turn on logging with --logging=debug or turn it down to serious

only errors with --logging=error

  • Turning on subsystem logs is easy: just run meru with the command

line argument --ogrelog=debug or --ogrelog=all of --ogrelog=info or any level

  • You can turn off logging by doing ./configure --disable-logging to

avoid most performance effects

  • You can tune what and where prints out in logs by selecting various

options from

    • --logfile=log.txt Choose which file to write to
    • --log-write-stdout=0 Choose not to write to stdout terminal
    • --log-write-stderr=1 Choose to write to stderr terminal
    • --log-time=0 Choose not to write out timestamps
    • --log-thread=0 Choose not to write threadid out
    • --log-index=0 Choose not to write index # to log
    • --log-function=1 Choose to log which function printed the message
    • --log-fileline=0 Choose not to log which file and line number the

message was printed on

    • --log-leveltype=0 Choose not to log the level of the log

(debug,warning,info,etc)