ICub Documentation Guidelines

From Wiki for iCub and Friends
Jump to navigation Jump to search
The correct title of this article is iCub Documentation Guidelines. The initial letter is shown capitalized due to technical restrictions.

Introduction

Ideally, all software is complemented both by informative in-line source code comments and by helpful external documents (such as tutorials, user manuals, and reference manuals). We strongly encourage contributors to provide this type of external documentation, but it is not mandatory. Instead, we depend on well-documented in-line source code. We use the Doxygen tool to extract source code comments and automatically create supporting documentation. The source code comments that are used by Doxygen must be identified by certain markup conventions and in the following we will distinguish between comments that are intended for automatic extraction and document creation by Doxygen and those that are intended only to enhance and explain the source code. However, we will provide guidelines for both types of comments.

Contributing Standards

In creating these standards, we have drawn from several sources. These include:


  • GNU Coding Standards
  • Java Code Conventions
  • C++ Coding Standard
  • The EPFL BIRG Coding Standards ;
  • The Doxygen User Manual


The standards set out in this document represent an attempt to find a balance between specifying too much (no one will read or use them) and specifying too little (the desired consistency won't be achieved).


Source Code Documentation

Introduction

Programs should have two kinds of comments: implementation comments and documentation comments.


Implementation comments are those which explain or clarify some aspect of the code. They are delimited by /* ... */ and //.


Documentation comments are intended to be extracted automatically by the Doxygen tool to create either HTML or LaTeX documentation for the program. They are delimited by /** ... */. Documentation comments are meant to describe the specification of the code from an implementation-free perspective. They are intended to be read by developers who won't necessarily have the source code at hand. Thus, documentation comments should help a developer understand the usage of the program, rather than its implementation.


Comments should be used to give overviews of code and provide additional information that is not readily available in the code itself. Comments should contain only information that is relevant to reading and understanding the program.


Information about how the executable should be compiled and linked or in what directory it resides should not be included as a comment. This information should go in the README file.


All comments should be written in English.


Implementation Comments

Programs can have four styles of implementation comments: block, single-line, trailing, and end-of-line.

Block Comments

Block comments are used to provide descriptions of files, methods, data structures, and algorithms. Block comments may be used at the beginning of each file and before each method. They can also be used in other places, such as within methods. Block comments inside a function or method should be indented to the same level as the code they describe.


A block comment should be preceded by a blank line to set it apart from the rest of the code.

  /*
   * Here is a block comment. 
   */

Single-Line Comments

Short comments can appear on a single line indented to the level of the code that follows. If a comment can't be written in a single line, it should follow the block comment format.

  if (condition) {

     /* Handle the condition. */

     ...
  }

Trailing Comments

Very short comments can appear on the same line as the code they describe, but should be shifted far enough to separate them from the statements. If more than one short comment appears in a segment of code, they should all be indented to the same level.

  if (a == b) {
     return TRUE;                 /* special case */
  }
  else {
     return general_answer(a);    /* only works if a != b */
  }

End-Of-Line Comments

The // comment delimiter can comment out a complete line or only a partial line. It shouldn't be used on consecutive multiple lines for text comments. However, it can be used in consecutive multiple lines for commenting out sections of code. Examples of all three styles follow.

  if (foo > 1) {

     // look left
     ...
  }
  else {
     return false;  // need to explain why
  }

  //if (foo > 1) {
  //
  //   // look left
  //   ...
  //}
  //else {
  //   return false;  // need to explain why
  //}

The First Block Comment

The first implementation block comment in every file should be the copyright and licence notice. Cut and paste the comment block below, inserting the year, name of author, and email address.

/* 
 * Copyright (C) <year> RobotCub Consortium, European Commission FP6 Project IST-004370
 * Author <name of author>
 * email:   <firstname.secondname>@robotcub.org
 * website: www.robotcub.org
 * Permission is granted to copy, distribute, and/or modify this program
 * under the terms of the GNU General Public License, version 2 or any
 * later version published by the Free Software Foundation.
 *
 * A copy of the license can be found at
 * http://www.robotcub.org/icub/license/gpl.txt
 *
 * This program 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
*/

This text is not included in a documentation comment (see below) because we don't want it to be extracted into the documentation by Doxygen. The documentation will contain its own GNU FDL license.


The comment should be placed at or close to the beginning of the file.

Documentation Comments

Preliminaries

Documentation comments describe classes, constructors, destructors, methods, members, and functions. The Doxygen documentation system is used to extract the documentation comments and create external documentation in HTML or LaTeX. Although Doxygen supports several documentation formats, we will stick to the Javadoc format as it is widely-accepted and it facilitates visually-pleasing and unobstrusive comments.


Each documentation comment is set inside the comment delimiters /** ... */. Within this comment, several keywords are used to flag specific types of information (e.g. @param, @see, and @return). We will treat each of these below by way of example.


Documentation comments are placed in front of a declaration or definition. Although Doxygen allows documentation comments to be placed in other places, such as after a declaration, in another location, or in another file, we will stick to the convention that documentation comments are placed directly in front of a declaration or definition.


Note that blank lines are treated as paragraph separators and the resulting documentation will automatically have a new paragraph whenever a blank line is encountered in a documentation comment.

Brief and Detailed Descriptions

For each code item (class, constructor, destructor, method, member, and function) there are two types of descriptions, which together form the documentation: a brief description and detailed description. Both should be provided. Having more than one brief or detailed description is not allowed.


As the name suggests, a brief description is a short one-liner, whereas the detailed description provides longer more detailed documentation.


As noted above, we use the JavaDoc style so that the brief description is automatically taken from the first line of the comment block and it is terminated by the first dot followed by a space or new line. For example:


/** Brief description which ends at this dot. Details follow
 * here.
 */

If there is one brief description before a declaration and one before a definition of a code item, only the one before the declaration will be used.


If the same situation occurs for a detailed description, the opposite applies: the one before the definition is used and the one before the declaration will be ignored.

In short, brief descriptions before declarations have precedence over brief descriptions before definitions; detailed descriptions before definitions have precedence over detailed descriptions before declarations.


We recommend that you avoid confusion and simply put all documentation comments, i.e. brief and detailed descriptions, before declarations in the interface (.h) file.


Note that to use the JavaDoc style JAVADOC_AUTOBRIEF must be set to YES in the Doxygen configuration file.

The First Documentation Comment

All source files should begin with a documentation comment that lists the program or class name, version information, and date, as follows.

/** @file <filename> <one line to identify the nature of the file>
 *
 * Version information
 *
 * Date
 *
 */


Module Documentation Comment

The #include file for an iCub module (i.e. the interface file) should have an implementation block comment which provides a clear summary of the function and usage of that module, as follows.

/** 
 * @ingroup icub_module
 *
 * \defgroup icub_<moduleName> <moduleName>
 *
 * detailed description of the module goes here ....
 *
 *
 * \section lib_sec Libraries
 *
 * YARP.
 *
 * \section parameters_sec Parameters
 * 
 * Command-line Parameters
 * 
 * The following key-value pairs can be specified as command-line parameters by prefixing -- to the key 
 * (e.g. --from file.ini. The value part can be changed to suit your needs; the default values are shown below. 
 *
 * - <key> <value>           
 *   <description>
 *
 * - ...
 *
 *
 * Configuration File Parameters
 *
 * The following key-value pairs can be specified as parameters in the configuration file 
 * (they can also be specified as command-line parameters if you so wish). 
 * The value part can be changed to suit your needs; the default values are shown below. 
 *   
 * - <key> <value>           
 *   <description> 
 *
 * - ... 
 *
 * 
 * \section portsa_sec Ports Accessed
 * 
 * - <portName>              
 *   <description>
 * 
 * - ...
 *                      
 * \section portsc_sec Ports Created
 *
 *  Input ports
 *
 *  - <portName>
 *    <description>
 *
 *  - ...
 *
 * Output ports
 *
 *  - <portName>
 *    <description>
 * 
 *  - ...
 *
 * Port types 
 *
 * The functional specification only names the ports to be used to communicate with the module 
 * but doesn't say anything about the data transmitted on the ports. This is defined by the following code. 
 *
 * - <portType>   <portName>        
 *
 *
 * \section in_files_sec Input Data Files
 *
 *  - <fileName>
 *    <description>
 *
 * \section out_data_sec Output Data Files
 *
 *  - <fileName>
 *    <description>
 *
 * \section conf_file_sec Configuration Files
 *
 *  - <fileName>
 *    <description>
 * 
 * \section tested_os_sec Tested OS
 *
 * Linux and Windows
 *
 * \section example_sec Example Instantiation of the Module
 * 
 * <moduleName> <parameter list>
 *
 * \author <Your Name>
 * 
 * Copyright (C) <year> RobotCub Consortium
 * 
 * CopyPolicy: Released under the terms of the GNU GPL v2.0.
 * 
 * This file can be edited at src/<moduleName>/src/<moduleName.h>.
 * 
 **/

Documenting Classes

There should be one documentation comment per class or function. This comment should appear just before the declaration:

/**
 * A test class. A more elaborate class description.
 */
 
class Test {
   
   public:
 
   /**
    * An enum.
    * More detailed enum description.
    */
 
   enum Tenum {
      TVAL1, /**< enum value TVAL1 */
      TVAL2, /**< enum value TVAL2 */
      TVAL3  /**< enum value TVAL3 */
   };
 
   Tenum *enumPtr;  /**< enum pointer.  Details. */
   Tenum  enumVar;  /**< enum variable. Details. */
 
   /**
    * A constructor.
    * A more elaborate description of the constructor.
    */
 
   Test();
 
   /**
    * A destructor.
    * A more elaborate description of the destructor.
    */
 
   ~Test();

   /**
    * a normal member taking two arguments and returning an integer value.
    * @param a an integer argument.
    * @param s a constant character pointer.
    * @see Test()
    * @see ~Test()
    * @see testMeToo()
    * @see publicVar()
    * @return The test results
    */
 
   int testMe(int a, const char *s);

   /**
    * A pure virtual member.
    * @see testMe()
    * @param c1 the first argument.
    * @param c2 the second argument.
    */
 
   virtual void testMeToo(char c1,char c2) = 0;
 
   /**
    * a public variable.
    * Details.
    */
 
   int publicVar;
 
   /**
    * a function variable.
    * Details.
    */
 
   int (*handler)(int a,int b);
};

Doxygen also allows you to put the documentation of members (including global functions) in front of the definition. This way the detailed documentation can be placed in the source file (definition) instead of the header file (declaration). Recall the point we made above about the precedence of definition and declaration regarding brief and detailed descriptions, and the recommendation that you put all documentation comments in the header (i.e. interface) file.


Top-level classes are not indented but their members are. The first line of a documentation comment is not indented but subsequent documentation comment lines each have one space of indentation (to align the asterisks vertically). Members, including constructors and destructors, have three or four spaces for the first documentation comment line (depending on which indentation standard you are using) and five spaces thereafter.


If you need to give information about a class, method, member, or function that isn't appropriate for documentation, use an implementation block comment or single-line comment immediately after the declaration. For example, details about the implementation of a class should go in such an implementation block comment following the class statement, not in the class documentation comment.


Documentation comments should not be positioned inside a method or a constructor definition block, because Doxygen associates documentation comments with the first declaration after the comment.


Documentation comments should, as a bare minimum, state:

  • What the function or method does.
  • What arguments it is passed, their types, and their use.
  • What arguments it returns, their types, and their use.
  • What the return type is, if any, and what it signifies.

Putting Documentation after Members

If you want to document the members of a file, struct, union, class, or enum, and you want to put the documentation for these members inside the compound, it is sometimes desired to place the documentation block after the member instead of before. For this purpose you should put an additional < marker in the comment block. For example:

   int var; /**< Detailed description after the member */

Warning: These blocks can only be used to document members and parameters. They cannot be used to document files, classes, unions, structs, groups, namespaces and enums themselves.

Documenting Global Code Items

To document a member of a C++ class, you must also document the class itself. The same holds for namespaces. To document a global C function, typedef, enum or preprocessor definition you must first document the file that contains it. This causes a problem because you can't put a document comment `in front' of a file. Doxygen allows code items to be documented by putting the document comment somewhere else but you must then identify the code item being documented with a structural command.


To document a global code item, such as a C function, you must document the file in which they are defined by putting a document comment with file structural command

/** @file */

in that file. Usually this will be a header file. Here is an example of a C header named structcmd.h.

/** @file structcmd.h  A documented header file ... 
 * These are the functions ...
 */


/** Opens a file descriptor.
 * @param pathname The name of the descriptor.
 * @param flags Opening flags.
 */
int open(const char *,int);


/** Closes the file descriptor .
 * @param fd The descriptor to close.
 */
int close(int);
 
 
/** Writes \a count bytes from \a buf to the filedescriptor \a fd.
 * @param fd The descriptor to write to.
 * @param buf The data buffer to write.
 * @param count The number of bytes to write.
 */
size_t write(int,const char *, size_t);