Old Coding standards

From FIFE development wiki
Jump to: navigation, search

This article is outdated and is just stored for archive purposes. Archived.png

This article became outdated and is just stored for archive purposes in this wiki. There are several reasons why an article could become outdated. The development team may have decided to use a different concept or even the author itself felt that the article is not really up-to-date with the current development status of the project anymore.

This artice is for the C/C++ coding standards. For the python guidelines see Python coding standards

Introduction

This article depicts the common rules of programming style that the FIFE developers have agreed upon to follow.

Files

  • Headers files end with .h
  • Source files end with .cpp
  • Only one class per h/cpp file. (With a exception for classes that are extremely simple and clearly belong together.)
  • The files should be named after the (main)class they implement, but all in lowercase.

Naming Conventions

  • Class names start with a capital letter (Example: class MapView)
  • Class names should not contain underscores.
  • Class members start with a prefix m_ (Example: class MapTile { /*...*/ int m_roofshift_x; }; )
  • Member variables and are all lowercase. (Example: int m_mymembervar;)
  • Parameter variables have no prefix and are also all lowercase. (Example: int myparamvar;)
  • Local variables have no prefix and are all lowercase. (Example: int mylocalvar;)
  • Function names start with a small letter (Example: bool isRoofVisible())

Coding Style

Braces

  • All braces use the following format.
if (x == y) {
    // ...
} else if (x > y) {
    // ...
} else {
    // ...
}
while (condition) {
    // ...
}
for (;;) {
    // ...
}
rtype functionName() {
    // ...
}
  • Even for trivial if statements always use the brace syntax.
if (x == true) {
    return;
}

This is clearer, less likely to cause future errors and has no effect on speed.

Indentation & Whitespace

  • Indentation is done by a real tab.
  • The content of a namespace is indented.
  • Don't leave whitespace at the end of lines.
  • Code after private:, public:, protected: and case foo: is indented.
  • Emacs people: Emacs may use a mixture of spaces and tabs to indent. Make sure this feature is disabled.

Type Safety

  • Don't use a #define when an enum or "static const int" is also possible.
  • Do not use the C-style casts; instead use static_cast, dynamic_cast and reinterpret_cast (if really necessary).
  • Avoid const_cast.
  • Be const-correct.

Includes

  • Try to use forward declarations rather to include other headers to reduce compiletime.

Platform specific includes

  • One of the issues with cross platform engine development are different include paths on different platforms. The FIFE team decided to introduce a set of helper include files to address this issue. You use these files instead of including the platform specific headers directly. Include these files after headers of the C++ std library but before any other 3rd party headers.
// Instead of including any OpenGL headers directly, use:
#include "video/opengl/fife_opengl.h"

// Instead of including the boost unit test header <boost/test/unit_test.hpp> directly, use for tests that reside in tests/core_tests:
#include "fife_unit_test.h"

// Instead of including any OpenAL headers directly, use:
#include "audio/fife_openal.h"

// Instead of including the C99 stdint.h header directly, use:
#include "util/base/fife_stdint.h"

// Instead of including the cmath header directly, use:
#include "util/math/fife_math.h

Variables

  • Don't use global variables.
  • Don't abuse the singleton objects so that they become global variable repositories. If you can't access a variable easilly from where you are you probably shouldn't be accessing it from there. This is a rule of thumb, not to be enforced strictly.
  • Declare 1 variable on each line.
int32_t x, y, z; // Wrong
int32_t x; // Correct
int32_t y;
int32_t z;
  • Align variable declarations as shown. This makes the code more readable.
int32_t        variable1;
DWORD          variable2;
std::string    string1;
  • Always initialize variables, and when initializing groups of variables align the code as shown.
variable1  = 0;
variable2  = 0;
string1    = "";
  • Avoid magic numbers as far as is possible. Replace them with const ints with descriptive names. The compiler will resolve this down to the exact same code, but it is much more readable.
  • When declaring pointers or references, the * or & is placed beside the type, not the variable name
int32_t* intpointer;
int32_t& intreference;
  • Use native types wherever possible. It is not necessary to "optimise" a loop counter by making it a uint8_t. Ideally, the use of such types would be restricted to three types of places:
    • dealing with saving or loading the data (e.g. serialisation/deserialisation routines)
    • transmitting data over a network
    • interfacing with external libraries, if those libraries absolutely insist.

Functions

  • Keep your functions simple.
  • Small functions that should be inlined go to the header file but after the class.
  • Use default parameters instead of inlined overloaded functions if you don't have a reason not to do so.

so don't write:

       inline void doSomething() {     // Wrong
           doSomething(0);
       }

       void doSomething(int32_t x) {
           ....
       }

but:

       void doSomething(int32_t x = 0) {   // Correct
           ....
       }

Multiple Inheritance

  • In case you feel tempted to use multiple inheritance, read this first: [1] (even the whole article is a good read).
  • In most of the cases, you can avoid multiple inheritance altogether with proper design. If you still feel urge to use it, try to use pure interfaces (no method implementations in addition to empty destructor). Prefix these classes with 'I'-letter (e.g. ITriggerController)
  • If you still feel that implementation multi-inheritance is the way to go, discuss this first with other developers.

Friend declarations

In general, don't use friend declarations. Friends tend to get overused, since at first sight they provide quick and easy solution for problem at hand. In many cases however, they violate encapsulation and decrease modularity. There are cases where friends might be beneficial, but consult other developers before making the decision.

Error Handling

  • Use exceptions when something exceptional has happened and cannot be recovered from. Prefer to make an entry in the FIFE log and somehow recover. See the Engine Development Philosophies document for more info on exceptions.
  • Constructors should always throw an exception on error conditions.
  • Destructors should never throw an exception.

Sample Source Files

Template source files can be found from svn:

  • header: [2]
  • implementation: [3]

Types

Integer Types

Specific integral types
Specifier Equivalent on 64 bit platform Equivalent on 32 bit platform Signing Bits Bytes
int8_t signed char signed char Signed 8 1
uint8_t unsigned char unsigned char Unsigned 8 1
int16_t short short Signed 16 2
uint16_t unsigned short unsigned short Unsigned 16 2
int32_t int int or long Signed 32 4
uint32_t unsigned int unsigned int or unsigned long Unsigned 32 4
int64_t long long long Signed 64 8
uint64_t unsigned long unsigned long long Unsigned 64 8

Complexity Management

  • FIFE is organized into distinct, layered modules. Understand the intended structure, read Architecture Documentation.
  • In general, avoid introducing cyclic dependencies between modules (and even classes and source files). Uni-directional dependencies increase modularity.
  • Having modular system has the following benefits
    • Loosely coupled system is easier to maintain
    • Having defined interfaces between modules, you know which parts of the system your changes are possibly going to affect (thus work division gets easier)
    • Compile times get shorter
    • System is easier to understand
    • Further reading:
  • High level structure is enforced with source analyzers, which are run along other tests. Run tests always before making a commit

Commenting

The level of commenting outlined here may seem excessive, but it will make the code much easier to understand when a new coder has to work with the system, something that will inevitably be happening in an Open Source project like FIFE. So please, don't become lax with the commenting.

Headers

Implementation

  • Try to write code someone else understands without any comment.
  • If you need to do something uncommon, or some special trick, comment.
  • Don't comment on something obvious.

Commenting Methods

All methods must be documented, no matter how trivial. The method description preceeds its declaration in the header file and uses standard doxygen notation. For simple accessor functions and things of similar complexity comments along the lines of the following are acceptable.

/** Short function description
 * 
 * @param p1 Short desc
 * @return Short description of return val
 */
rtype Function(ptype p1);

All methods' parameters and return types must be described. This is so that the doxygen generates documentation can be of real use. functions who's use isn't obvious require longer descriptions, which should include a more detailed description of its task as well as a sample of its use. Make the example as illustrative as possible.

/** Short function description
 *
 * Detailed description
 * Example: rtype rVal = complicatedFunction(Param1, Param2);
 *
 * @param p1 Description of parameter
 * @param p2 Description of parameter
 * @return Description of return value.
 */
rtype complicatedFunction(ptype1 p1, ptype2 p2);

Comments inside the body of a method should be kept to a minimum in simple functions again. But in large functions, especially those that encapsulate key algorithms, relatively detailed descriptions of how the code is opperating will make it much more maintainable. These should be kept to one of two line comments using the // syntax.

// converts from screen space to world space
x += xoffset;
y += yoffset;
// checks to see if an image is already loaded.
bool Loaded;
Loaded = Image->getImageData() != 0;

Commenting Variables

Member variables should all be commented. Either individual variables, or blocks of variables with a similar function, as long as all member variables are in some way described. This is not a substitute for good variable names, but rather a way to make clear the use of each member variable.

// Window dimensions in pixels.
int m_windowwidth;
int m_windowheight;
// SDL_Surface which represents the renderable area of the screen.
SDL_Surface* m_screen;

Parameters are all commented in the method description comment block so additional comments are unnecessary.

Descriptions of local variables shouldn't be necessary as long as descriptive names are used.

Commenting engine extensions

Gotchas

Along with other comments, use gotcha keywords to mark unfinished tasks in the code. Consider a robot will parse your comments looking for keywords, stripping them out, and making a report so people can make a special effort where needed.

  • Gotcha Keywords
    • TODO: topic
      • Means there's more to do here, don't forget.
    • FIXME: topic
      • means there's a Known bug here, explain it and optionally give a trac id

License

  • If you directly copy and paste code from another project the original copyright header needs to stay in place! Don't add a FIFE header to the file in this case.
  • If you used portions of code from other projects and integrated it into project files, add the FIFE header at the top of the file but add an additional remark after it that states the origin of the copied code parts.
  • You can use this example as a template in this case:
/***************************************************************************
 * Note! FIFE event channel borrows heavily from ideas of Guichan library  *
 * version 0.6                                                             *
 ***************************************************************************/

SVN Commits

See SVN guidelines.

Trac rules

Please follow the rules outlined at the Trac Ticket Tracker article.

References