Development:Style Guide

From Adonthell
Jump to: navigation, search

Below you will find the basic conventions used in the Adonthell source code. Being familiar with them will ease your own understanding of the existing code and by following them you'll help others to better understand your code too.

Contents

Indentation

No matter who wrote a file, it must be readable by anybody. The beginning of readability is a correct indentation. Here are a few rules to follow:

  • Block indentation is set to 4 characters.
  • A space should be placed before/after every operator and separator.
  • Air your code. Skip lines between blocks, and don't hesitate to comment when it is useful.
  • In your classes declarations, make the public interface appear AS SOON AS POSSIBLE, so users of your class doesn't need to search through the entire file.

Here is some sample code:

int main (int argc, char * argv [])
{
    int i;

    for (i = 0; i < 10; i++)
    {
        int ret = myfunc (0, 1, 2);
        if (ret <= 10) return ret;
    }

    return 0;
}

Documentation System

The API documentation is created by Doxygen from the source code. Doxygen is a very powerful documentation system that allows programmers to quickly document their code with class references, diagrams (inheritance, class hierarchy, ...) and many other useful things with very small effort, letting them concentrate on the code rather than the documentation. The programmer documentation can easily be generated provided the source code (or rather the header files) are correctly commented. For more informations, have a look at Doxygen's own documentation which is available at [1].

Your classes must all be clearly documented, to allow other developers to use them, and yourself to remember how they work. You'll have to document at file level, class level and member level.

Documenting at file level

EVERY file of Adonthell HAS TO start with the following:

/*
  Copyright (C) <year>   <your name>
  Part of the Adonthell Project http://adonthell.linuxgames.com
 
  Adonthell is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
  
  Adonthell is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with Adonthell; if not, write to the Free Software Foundation, 
  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
 
/**
 * @file   <filename>
 * @author <yourname> <<your_email@adress>>
 * 
 * @brief  <Briefly describe what's in this file>
 */

The first block is for Copyright issues. You clearly show that this file is distributed under the terms of the GPL v2 or later; that it comes with no warranty and that you are the copyright holder of the file. The Copyright line has to show all the years this file has been worked on. Several persons may hold the copyright of a file. In this case, put one Copyright line per person.

The second block is for referencing this file in Doxygen's documentation system. It's quite explicit and MANDATORY if you want to document the classes in this file.

Documenting at class level

Each class must have a little documentation block explaining what it does. Moreover, you can't document a class member if the class itself isn't documented. Just put a Doxygen block before your class and explain what it is for:

/**
 * This very powerful class blah blah....
 * blah blah blah blah blah
 * blah blah blah blah.
 *
 * @bug Uh, I still have to write the members.
 *
 */
class my_very_cool_class
{
    ...
}

Don't hesitate to use Doxygen's special tags, like \note or \bug.

Documenting at member level

Once your class is briefly described, you can start the "true" documenting, that is, clearly and precisely describe your public interface. Once again, everything is better explained in Doxygen's own documentation, but here is an example for a member function:

class my_class
{
public:
    /**
     * Returns the square root of the parameter.
     * @param a_number Number to calculate the square root of.
     * @return Square root of a_number.
     */
    float sqrt (float a_number); 
}


Once you have done this, and rebuild the documentation, your class will appear in the Class Hierarchy diagram, with it's own documentation page and automatically generated Inheritance Diagram. /* Have a look at the Image Class Page for a sample of the result you can expect, and the image.h file (see the source code) to see how it has been done. */

Naming Conventions

There are several different more or less popular ways to name your functions and classes. Depending on what you like, you could call the same function perform_something () or PerformSomething (), etc. ... To keep the interface as clear and homogeneous as possible, here are a few rules to follow when naming your classes and functions:

  • Use lower cases, and '_' as a separator if your function name has several words (ex: perform_something ()).
  • Member access functions should be as short as possible. For read-access, use the most direct name possible (i.e. length () for the length of an object), for write access, use set_member style names (set_length (u_int16 l)). Of course, the member itself should then have a name different than length. Making it uppercase (Length) is widely used through the code to denote member variables - but you are free to do something else if you don't like that (m_length or length_ can be seen at places).
  • Methods returning something more complicated than a simple data type (i.e. functions that return a pointer to a complex data structure, etc...) should use a get_<name> style instead. For example, a method returning an image of an animation should be named get_image ().
  • If your class is static, the "manual" constructor/destructor should then be named respectively init () and cleanup ().

Let's see a concrete example of this naming convention through a class interface:

  class animation
  {
  public:
      // Constructor
      animation (); 
        
      // Destructor
      ~animation ();
 
      u_int16 length () const
      {
          return Length;
      }
 
      u_int16 height () const
      {
          return Height;
      }
 
      image * get_image (const u_int16 & pos) const
      {
          return Frame[pos];
      }
 
      ...
 
  private:
      u_int16 Length;
      u_int16 Height;
      vector <image> Frame;
  }

Method Calling Conventions

Most often you will work with objects created by yourself or someone else. Passing such objects to methods by value has to be absolutely avoided, for performance and bug issues. Passing a big object by value to a function requires memory to be allocated for the function's object, and of course the copy-constructor and destructor to be called. Needless to say, that without a copy-constructor most complicated objects won't be passed correctly, and this is a source of difficult bug tracking.

Instead of passing your objects by value, you'll pass them by reference. That way, no memory is allocated, and actions are performed directly on your object. To make it obvious which methods modify the object you're passing and which don't, the following conventions has been set up:

When a function requires an object and doesn't modify it, pass it by const reference.

    void doesnt_modify (const myclass & myobject);

When a function requires an object and modifies it, pass it by address.

    void modify (myclass * myobject);

Note: Of course, this doesn't apply to your operator overloading functions which are obviously explicit. And, to make sure nobody will ever pass one of your objects by value, declare the copy-constructor as private:

class myclass
{

...

private:
    myclass (myclass & src);
};

This will cause a compilation error if someone ever tries to pass an object of your class by value.

Personal tools
Namespaces

Variants
Actions
Navigation
Exits
Tools