Programming rules

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:

Here is a 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 document you are currently reading is generated 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 a 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 http://www.doxygen.org.

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:
 /*
   $Id:

   Copyright (C) <year>   <your name>
   Part of the Adonthell Project http://adonthell.linuxgames.com

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
 */


/**
 * @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 ; 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 $Id: line is for the CVS system. It will put useful information on this line when the file will be committed, indicating who last modified this file, when, and which version number it is.

The second block is for referencing this file into 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.

Method naming

General naming conventions

There are several different more or less popular ways to name your functions and classes. Depending on what you like, you can 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:

Let's see a concrete example of this naming convention through a class interface:
   class animation
   {
   public:
       // Constructor
       animation (); 
       
       // Destructor
       ~animation ();

       u_int16 length ()
       {
           return length_;
       }

       u_int16 height ()
       {
           return height_;
       }

       image * get_image (u_int16 pos)
       {
           return frame[pos];
       }

       .....

   private:
       u_int16 length_;
       u_int16 height_;
       vector <image> frame;
   }
 

Constructor selection for Python

As Python can only have one constructor per class, you have to choose which one will be available. The default constructor often makes sense ; but if your class requires a constructor with arguments, then you can transgress this rule of course. In any case, be aware that you need to be able to reach the state of ANY of your C++ constructors from Python by using the available constructor plus one or more of your class methods. To select which constructor is available, embed the others with a ifndef SWIG directive.
 class image
 {
 public:
     // Default constructor (the one available from Python) 
     image ();
    
 #ifndef SWIG
     // Creates an image of size (l, h)
     image (u_int16 l, u_int16 h); 
 #endif

     // This method makes it possible to reach the state of the second constructor
     // from Python by doing: im = image (); im.resize (l, h); 
     // Moreover, it's also useful in other cases.
     void resize (u_int16 l, u_int16 h);
   ...
 };
 

Making overloaded methods and operators available for Python

SWIG doesn't like overloaded functions and operators, and will print a warning if it meets one. But the functions or operators you have overloaded have to be available from the Python interface. To make them available, you should us a ifdef SWIG directive to declare another inlined function that matches the overloaded function or operator. An example is better than a long explanation:
 class myclass
 {
 public:

     ......
    /**
     * Drawing method 1
     */ 
     void draw (int x, int y);
#ifndef SWIG
    /**
     * Drawing method 2
     * @attention Not available from Python. Use draw_part () instead.
     * @sa draw_part ()
     */ 
     void draw (int x, int y, int l, int h);
#endif
    /**
     * Synonym of draw (x, y, l, h) to guarantee it's availability from Python.
     */ 
     void draw_part (int x, int y, int l, int h)
     {
         draw (x, y, l, h);
     }

    /**
     * Copy operator (similar to copy ()).
     *
     * @attention Not available from Python. Use copy () instead.
     * @sa copy ()
     */
     myclass& operator = (const myclass & src);

     /**
     * Synonym of operator = to guarantee its access from Python.
     *
     * @sa operator = 
     */
     void copy (const myclass& src) 
     {     
         *this = src; 
     }    
     ...

 }
 

Don't forget to comment your methods accordingly to their access.

Functions synonym to Operators should have explicit names. As an operator could have several meanings (+ could be said "add" or "concat", for example) you are free to choose whatever name fits best with your usage.

Argument passing conventions

Object passing

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 performances 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 correctly passed, and this is a source of useless 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:

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.

Generated on Wed Mar 9 08:08:55 2011 for Adonthell by  doxygen 1.5.9