E-Cell 4 Coding Guide rev. 4

authors:Koichi Takahashi
date:editing

DRAFT DOCUMENT – This is intended to eventually replace the rev. 3.

Introduction

This document describes the coding standard for the E-Cell System Version 4 development and related projects.

To keep it compact and handy, this document primarily intends to disambiguate things that are useful in giving standardized appearance to program codes, such as naming conventions and file layout. Many tips that are supposed to be obvious to intermediate to advanced programmers are not included (such as that C-style casts should be avoided as much as possible in C++). E-Cell project coders are referred to more comprehensive documents such as Effective C++ and More Effective C++ for C++, and Python Enhancement Proposal 8, or PEP 8, PEP 20, PEP 257 and PEP 287 for Python coding.

Common

Indentation / Punctuation

  • Keep lines to 79 characters or less.

  • Indent with 4 spaces.

  • Do not use tabs for indentation. Use exclusively spaces.

  • Do not put whitespace immediately inside parentheses, brackets or braces.

  • Do not put whitespace immediately before comma, semicolon or colon.

  • Do not put whitespace immediately before the open parenthesis that starts the argument list of a function call, indexing or slicing.

  • Put a space after a , or :, when it is not the last character in the line:

    f(a, b, c)
    [123: 456], {"abc": "def", "ghi": "jkl"}
  • Insert spaces around binary operators, but not around unary operators:

    ((a + b) * c) * *d--

    not:

    ((a+b)*c)*(*d--)
  • Do not use more than one space around an assignment (or other) operator to align it with another:

    x = 1
    length = 2
    

    not:

    x      = 1
    length = 2
    
  • NOTE: above rules are consistent with Python Enhancement Proposal (PEP) 8.

Names

General

  • Do not abbreviate

    (There are exceptions. See below).

Constants and variables

  • Constants

    Use capital letters, words separated with underscores:

    SOME_CONSTANT
    
  • Variables and function/method parameters

    Use the underscore (‘_’) to separate words. Basically use lower case.:

    length
    max_length
    

    Prefer one-word names for function/method parameters:

    function(name, id)
    
  • Loop counters and iterators

    Local counters and iterators primarily used in a single loop may be one character alphabet; such as i, j, k, l, m, n in this order.

Classnames

  • Upper camel case must be used for names of all exposed classes constituting programming interface of the package:

    ClassName
    
  • Exception classes

    Names ending with Exception, Error and such are recommended:

    NonFatalException
    

Functions and methods

  • Use the underscore (‘_’) to separate words. Basically use lower case:

    function_name()
    method_name()
    
  • Prefer verb+noun form for functions and method names.

  • Factory methods

    create + classname or nature of the object to be created:

    create_Proxy()
    
  • Converter methods

    to + classname or nature of the target:

    to_Real()
    
  • Getters and setters

    get or set + the name of the attribute:

    get_length()
    set_length()
    
  • Boolean predicates

    is + adj., can + verb, has + past particle, verb, or verb + noun with the object as an implicit subject:

    this->is_empty()
    this->can_stop()
    
    self.has_attribute()
    self.contains()
    self.contains_key()

Style

  • Put one statement per line.
  • Initialize all members in constructors.

Python

General

Style

  • Do not use module variables as variables. Use only as constants.
  • Prefer properties to setter/getter methods when accessing members.

Comments

  • All functions, classes and methods that constitute programming interface of the module must be commented properly.
  • Use docstrings in reStructured Text format to document classes, functions etc.

Others

  • Use of pychecker is recommended.

Example

import numpy


MODULE_CONSTANT = 0


def some_module_function(a, b):
    '''Docstring.'''
    return a + b


class SomeClass:
    '''
    SomeClass docstring.
    '''
    CLASS_CONSTANT = 1
    class_variable = 'foo'

    def __init__(self):
        '''
        Constructor docstring.
        '''
        self.object_name = ''
        self.key = ''
        self.length = 0

    def set_length(self, length=0):
        '''
        Docstring for set_length.
        '''
        self.length = length

    def update_key(self, key):
        '''
        Docstring for update_key.
        '''
        self.key = key

C++

Files and Layouts

  • Names of C++ source files must end with .hpp or .cpp.

  • A public class must be contained in its own header file.

    Private and auxiliary classes may be contained in header files of other public classes.

  • Basic layout of a header file:

    #ifndef __FILENAME_HPP
    #define __FILENAME_HPP
    
    // #include directives
    
    // typedefs
    
    // auxiliary functions
    
    // private / auxiliary class declarations
    
    // main class declaration
    
    #endif /* __FILENAME_HPP */

Indentation / Punctuation

  • Indent in BSD/Allman style.

    if (a > 0)
    {
        something();
    }

    not:

    if (a > 0)
      {
        something ();
      }

    nor:

    if (a > 0) {
        something();
    }

    nor:

    if (a > 0) something();
  • Namespaces

    Do not indent the contents of top-level namespaces:

    namespace ecell
    {
    class Foo
    {
        ...
    };
    
    }

    not:

    namespace ecell
    {
        class Foo
        {
            ...
        };
    
    }
  • Do not omit brackets around a one-line block:

    if (a < b)
    {
        return;
    }

    not:

    if (a < b)
        return;
  • Do-while

    while must be on the same line as the closing brace.

    do
    {
        ++x;
    } while (x != y);

Names

  • Put an underscore ‘_’ after private member variables of a class:

    class Foo
    {
    private:
    
        int length_;
        Position& center_position_;
    };
  • Struct variables does not need the trailing underscore ‘_’:

    struct Bar
    {
        int length;
        Position& center_position;
    };

Classes and types

  • Use struct only when it is a data-carrying passive object.

    Passive here means that the object lacks behaviors other than setting up data (i.e. constructor, destructor, initialize(), reset() etc.), and accessing member variables to it is always done directly and not through methods.

  • You can define Interface class when it

    • has only public pure virtual and static methods except a virtual destructor.
    • has no non-static data members.
    • has no constructor, or protected constructor(s) that takes no arguments.
    • has no superclass or a superclass that is an Interface.

    A class name of such class may end with Interface, but this naming convension is not compulsory.

  • Basic layout of a class declaration:

    class Foo
      :
      public FooBase
    {
    
    public:  // optional
    
        // typedefs and other type-related stuff
    
    public:  // repeat this even if there is another public: above.
    
        Foo();    // constructor
        ~Foo();   // destructor
    
        // setter / getter methods
        void set_length(const int&);
        const int get_length() const;
    
        // other public methods
        void clear();
        void initialize();
        ...
    
        // operators
    
    protected:
    
        // protected methods
    
    private:
    
        // private methods
    
    protected:
    
        // protected member variables.
    
    private:
    
        // private member variables.
    
    
        int length_;
        Position& center_position_;
    };
  • Do not name types as a form of self-documentation.

    For example,

  • Use integer types defined in <stdint.h> such as int32_t and uint_64_t when you need a guarantee on the size of an integer. Do not use conventional C integer types such as short or long long to mean the size of an integer.

  • Use int for small integers such as loop counters.

Style

  • Prefer single, fixed ownership of objects.

  • When you have to handle pointers, first consider scoped_ptr, and then consider shared_ptr only when scoped_ptr is not appropriate.

  • Do not use #define for constants. Use const variables.

    const Int MAX_SIZE(100);

    not

    #define MAX_SIZE 100;
    
  • Use assert only to capture bugs. Otherwise use exceptions.

    e.g. Don’t use assert to check validity of user input.

Comments

  • All public classes and methods must be commented.
  • Make comments in Doxygen-Javadoc style.

Miscellaneous

Packaging

  • Comply with the Filesystem Hierarchy Standard.

Documentation

  • Use reStructured Text for text documents in the package.
  • Use DocBook version 4 for other documents (such as reference manuals and tutorials).

Appendices

Sample editor/formatter settings

Emacs

.emacs file may contain:

(add-hook 'c-mode-hook
          '(lambda ()
             (c-set-style "bsd")
             (setq c-basic-offset 4)
             (setq indent-tabs-mode nil)))
(add-hook 'c++-mode-hook
          '(lambda ()
             (c-set-style "bsd")
             (setq c-basic-offset 4)
             (c-set-offset 'innamespace 0)
             (setq indent-tabs-mode nil)))
(add-hook 'python-mode-hook
          '(lambda()
             (setq indent-tabs-mode nil)))

Eclipse

  1. Install astyle.
  2. Install Plugins
    • CDT
    • Pydev
    • Astyleclipse (optional)
    • Subclipse (optional)
  3. Window->Preferences->C/C++->Editor->Appearance->Insert space for tabs
  4. Astyle configuration.
    • Window->Preferences->C/C++->Code Formatter: Astylipse.
    • Window->Preferences->Astyle->style = ansi
    • Window->Preferences->Astyle->Other options as below or use ~/.astylerc.
  5. Pydev configuration.
    • Window->Preferences->Pydev->Tabe length = 4, Substitute spaces for tabs = yes, Use code folding = yes.
    • Check Pydev->Code Formatter->Use space after commas and Use space before and after parenthesis.

Artistic style code formatter for C++

The following gives somewhat acceptable results, though not perfect.

astyle --style=ansi --unpad=paren --pad=oper --convert-tabs