Home
About ISIS
Support
Download

ISIS 3

Documentation
Tutorials
Technical Documents

ISIS 2

Documentation
Tutorials
Technical Documents

Search

USGS

ISIS 3 Documentation


ISIS 3 Coding Standards and Style Guide

Coding standards for ISIS 3 developers (effective February 1, 2012).

Home

Table of Contents

  1. Introduction
  2. Formatting
    1. Indenting
    2. Line Length
    3. Padding
      1. Around Parentheses, Braces, and Brackets
      2. Method and Definition Calls
      3. Unary Operators
      4. Binary Operators
      5. Vectors and Lists
    4. Control Structures
      1. Braces
      2. Padding
    5. Continuing Lines of Code
    6. Logical Operators
    7. Pointers and References
    8. Source Code Documentation
  3. Naming Conventions
    1. Application Names
    2. Class Names
    3. Member Function Names
    4. Data Member Names
    5. Local Variable Names
    6. Enumeration Names
    7. Namespace Names
    8. Source Code File Names
      1. Object File Names
      2. Application File Names
  4. #Includes
    1. #Include Guards
    2. Ordering Library Includes
    3. Forward Class Declarations
  5. Documentation
    1. History Entries
      1. Formatting
      2. Author Tag
    2. Makefile Comments
  6. Source Code
    1. Structures
    2. Implementation Files
    3. Support Class Files
    4. Header Files
      1. Inline Members
      2. const Keyword
    5. Declaring & Initializing Variables
      1. Local Variable Declarations
      2. Initializing Variables
    6. Method Order in Implementation File
  7. Strings
    1. IString
    2. QString
    3. std::string
    4. Other Strings
  8. To Do

Introduction

This document will describe the coding standards for maintaining ISIS 3 source code. It was created to ensure that the ISIS 3 package is programmed for consistency, readability and ease of future maintenance. This document does not attempt to address every possible issue. However, the guidelines that have been outlined should not be deviated from, except under special situations.

Formatting

Indenting

The general indenting scheme for ISIS 3 is 2 spaces (no tabs). Wrapped lines of code should be indented a minimum of 4 spaces from the beginning line of the command. Programmers may choose to indent more than 4 spaces to make the code more readable. For example, it is common practice to indent a wrapped line to be contained inside the opening parenthesis when making a long method call as shown below.

For example:


            
            // The second and third lines are often indented to line up with the
            // appropriate opening parenthesis. 
            throw IException(IException::Unknown,
                                      "Camera missed planet or SPICE data off.",
                                      _FILEINFO_);
          

Return to Table of Contents

Line Length

Lines of code should not exceed 100 characters unless they cannot be wrapped. This may be difficult in a few cases, however there are little if any cases in which the 100 character limit must be broken. For function implementation, lines may be broken between the return type and class name scope or between input parameters as shown below.

For example:


            
            // Break lines between input parameters and indent to opening
            // parenthesis. Code inside the function is indented 2 spaces from the
            // beginning of the method return type. 
            vector<double> VeryLongClassName::ReallyLongFunctionName(int a,
                                                                     int b,
                                                                     int c) {
              statement1;
              ...
            }
            
            // Break lines between return type and class name and indent the
            // second line 4 spaces.  The input parameters are then indented 4 more
            // spaces for readability.  Code inside the function is indented 2
            // spaces from the beginning of the method return type. 
            vector< vector<double>, vector<double> >
                VeryLongClassName::ReallyLongFunctionName(
                    const vector<double, double> inputParameter1,
                    const vector<double, double> inputParameter2) {
              statement1;
              ...
            }
          

Return to Table of Contents

Padding

Around Parentheses, Braces, and Brackets

Padding is not used inside parentheses ( ) or angle brackets < > if the interior is short and simple. For embedded parentheses, padding may be used to make code more readable. For embedded angle brackets, padding is required between closing brackets. If the interior is not simple, programmers can also use padding in such a way to make the code more readable.

Externally, we use padding before opening curly braces. For example, a space should be added before opening curly braces for method definitions, namespace wrappers, enumeration definitions and control structures.

For example:

// No interior padding needed - single brackets
vector<double> vectName;

// No interior padding needed - brackets are not consecutive
vector<vector<double, double>, int>

// Padding needed outside parentheses, none needed inside
if (condition) {
statement;
}

// Use interior padding when closing parentheses or angle brackets
// are consecutive characters.

vector< int, vector<double, double> >
if ( (a && b) || (c && d) ) statement;

// Use padding before opening curly brace
namespace ISIS {
...
}

Return to Table of Contents

Method Definition and Calls

No space should be used between a method name and its opening parentheses. Padding inside and after parentheses was covered previously in this document, see Formatting Padding Around Parentheses, Braces, and Brackets.

For example:


             // Correct form 
            int functionName() {
            if ( success() )
            
            // Incorrect form has space after function name 
            int functionName () {
            if ( success () )
          

Return to Table of Contents

Unary Operators

There is no padding between variables and unary operators such as

For example:


             // Correct form 
            int count = 0; count++;
            if ( !success() )
            
            // Incorrect form has a space between the variable name
            // and unary operator. 
            count ++;
            if ( ! success() )
          

Return to Table of Contents

Binary Operators

Padding to be discussed

Return to Table of Contents

Vector and List Declarations

When declaring a vector or list data type, no space between the keyword and the opening angle bracket should be used. This is merely an aesthetic preference for consistency throughout ISIS 3.

For example:


            // Correct form - No outside padding
            vector<double>
            QList< QList<int>, QList<int> >

            // Incorrect form with outside padding
            vector <double>
            QList < QList <int>, QList <int> >
          

Return to Table of Contents

Control Structures

Braces

Most control structures require the use of braces for compound statements, or blocks, such as conditional structures (if - else), iteration structures (for, while, do - while), and exception structures (try - catch). For these structures the opening brace should appear on the line with the appropriate keyword that indicates the beginning of such a structure and the closing brace should appear on its own line.

For example:


            
            // The opening braces for each block appears on the same line as the
            // if and else keywords.  Closing braces have their own lines.
            if (condition) {
              statement;
            }
            else {
              statement 1;
              statement 2;
            }
          

Function definitions, class definitions and other similar structures that have multiple statements should follow a similar format.

Note that these guidelines apply only to compound statements, or blocks. For simple statements, control structures and function definitions may be written in a single line of code without braces. Control structures with multiple parts should use consistent formatting in each part. That is, if braces are used on any section, then they should be used on all sections.

Return to Table of Contents

Padding

Control structures that use parentheses (if, for, while, switch, catch). For these should have external padding around the parentheses. That is, there should be a single space before an opening parenthesis and one space after a closing parenthesis. If a control structure has a keyword immediately preceding an opening brace (try, else) there should be one space between the keyword and brace. For an example, see Control Structure Braces.

General padding guidelines have been previously covered in this document, see Formatting Padding Around Parentheses, Braces, and Brackets.

Return to Table of Contents

Continuing Lines of Code

Do not use a backslash to continue a line of code. This is not necessary in C++. For example, if a long string is being set, an end quotation can be used and the next line use a beginning quotation.


            string str =  "This string is very long and will need to be "
                          "continued on a second line.";
          

Return to Table of Contents

Logical Operators

The use of aliases for logical operators is prohibited in ISIS 3 . For example, a program must not contain the following aliases:

Prohibited Alias Use Logical Operator
and &&
or ||
xor ^
not !
not_eq !=
comp ~

Return to Table of Contents

Pointers and References

The asterisk for pointers (*) and the ampersand for references (&) should always be put on the variable name or method name when possible.

For example:


            
            // Pointer and reference go on the variable name
            int *var1;
            int &var2 = *var1;
            
            // On method prototypes, the pointers and references go next to the function or method
            //   name.
            int *function(const int &a);
            int *Class::method(const int &a);
            int &function(const int *a);
            int &Class::method(const int &a);
          

Return to Table of Contents

Source Code Documentation

Doxygen

Isis 3 uses the Doxygen documentation extraction software. Doxygen has extended the tag set of the javadoc documentation style, a systematic in-code documentation style that allows pertinent documentation to be extracted easily. Doxygen is just one of many software packages that are able to extract and use javadoc documentation for a variety of purposes, allowing us to take advantage of a wealth of documentation extractors, IDEs, and other tools on the market that make our lives simpler and more productive.

Return to Table of Contents

Using HTML

HTML can be used anywhere in your documentation. Keep it simple. Doxygen will "interpret" your HTML, so you may not get the desired effect. Best advice, avoid attempting special effects by just using the basic HTML formatting tags - bold, underline, pre, code, table (caption, tr, td, th), etc. and only when really necessary. Better yet, consider using the formatting tags in the Other Useful Tags section instead of HTML. Your plain old text will be pretty nicely rendered into paragraphs with automatically linked items and other bells and whistles. Keep your source readable: minimize formatting.

Return to Table of Contents

Autolinking

Class, method, variable, and other entity names will be automatically linked in the documentation. To prevent this for a specific occurence of a name, use a percent sign (%) in front of the name. For example, if you have a class name "Histogram" and you want to prevent the linking of the word "Histogram" in your description because it is not referring to the class but to an actual histogram, use "%Histogram" to prevent the word from being linked.

E-mail addresses and web addresses are also automatically linked. If a web address is particularly long, put it on its own line.

Return to Table of Contents

Naming Conventions

This section will cover the proper way to name applications, classes, functions, variables, enumerations, and namespaces and files.

Return to Table of Contents

Application Names

Application names are always all lower case. Existing parameter names should be checked before any new names are created. (Plans to create a standard parameter name document are currently underway.)

Return to Table of Contents

Class Names

Classes should be upper camel case. That is, the first letter should be capitalized and, if the class is a multi-word phrase, spaces are eliminated and each subsequent word should also begin with a capital letter. As a general rule, class names should be nouns.

**Note: There are 3 existing classes in ISIS 3 that do not follow this convention. The iString and iTime classes needed a prefix to distinguish them from the C++ system string and time classes. While these classes will not be changed at this time, in the event that similar classes are created, a capital letter I prefix should be used to remain consistent with the rest of ISIS 3.

For example:


            // Class names are upper camel case 
            ClassName
            IVector
            

Return to Table of Contents

Member Function Names

Member functions should be lower camel case, when possible. That is, the first letter should be lower case and, if the class is a multi-word phrase, spaces are eliminated and each subsequent word should begin with a capital letter. This should remain consistent throughout ISIS 3 except in two cases. Constructor and destructor methods must be upper camel case to match the class name. The other case in which this convention may not be followed is when a method overrides or overloads an existing method from its parent package. In these cases, clearly, the original method name must be kept. For example, some packages use underscore separated naming.

For example:


            
            // Ordinary member function names are lower camel case.
            functionName()
            
            // Constructor function names are upper camel case.
            ClassName()
            
            // Overridden member function from third party package keeps the name of
            // the original function.
            original_function_name()
          

All appropriate mutator and accessor methods should begin with set, has, or is. The get prefix should not be used for accessor methods, with the exception of overridden methods inherited from third party libraries.

For example:


            
            // All mutator methods begin with the 'set' prefix.
            void setSize();
            
            // The 'has' and 'is' prefixes are always used.
            bool hasKeyword();
            bool isIgnored();
            
            // The 'get' prefix is not used for methods that retrieve
            int size();
            Stretch stretch();
            
            // The 'get' prefix sometimes is required for overridden methods from
            // third party packages, such as the following method from QInputDialog.
            QString getText();
          

Return to Table of Contents

Data Member Names

ISIS 3 currently uses three types of data members: global, protected, and private. Note that global and protected data members should be avoided and public member data in classes is not permitted in ISIS 3.

Global variables should have the prefix g_ followed by a lower camel case name. Protected and private variables should have the prefix m_ followed by a lower camel case name.

For example:


            
            // Global variables use the 'g_' prefix.
            g_globalVariable
            
            // Member variables use the 'm_' prefix.
            m_memberVariable
          

Return to Table of Contents

Local Variable Names

Local variables should have lower camel case names. Names for local variables should be "meaningful" and documented when necessary. For example, names can describe what they represent or they can mimic the variable names of a mathematical formula or equation. If a piece of code represents a formula, it is advisable to document the original formula location and, when known, the meaning of a variable.

For example:


         bool LambertAzimuthal::SetGround(const double lat,
                                          const double lon) {
           ...
         
           // Variable names mimic the names of mathematical
           // variables in the formula found at
           // http://mathworld.wolfram.com/LambertAzimuthalEqual-AreaProjection.html
           //  KEY:
           //    VARIABLE    MEANING
           //    phi         given latitude, in radians
           //    lambda      given longitude, in radians
           //    phi1        center latitude, in radians
           //    lambda0     center longitude, in radians
           double phi = lat * PI / 180;
           double lambda = lon * PI / 180;
           double kPrime = sqrt(2/(1 + sin(phi)*sin(phi1)
                                     + cos(phi)*cos(phi1)
                                       *cos(lambda - lambda0);
           x = kPrime*cos(phi)*sin(lambda - lambda0);
           y = kPrime*(cos(phi1)
                       *sin(phi) - sin(phi1)*cos(phi)
                                   *cos(lambda - lambda0);
           ...
         }
         

Return to Table of Contents

Enumeration Names

Both the enumeration type name and enumerators inside the braces should be upper camel case.

For example:


/**
* Documentation for enumeration type.
*/

enum EnumTypeName {
FirstEnumerator, //!< Documentation for first enumerator
SecondEnumerator //!< Documentation for second enumerator
};

Return to Table of Contents

Namespace Names

Currently, the only namespace that is used is the ISIS namespace. However, if namespaces are added, they should be upper camel case. Also note that any new namespaces should be inside the ISIS namespace.

For example:


            // Namespaces are upper camel case.
            NamespaceName
          

Return to Table of Contents

Source Code File Names

In some situations, having multiple files with the same name (regardless of case sensitivity) might cause compiler errors. To prevent these problems the use of the same file name anywhere in ISIS should be avoided, when possible.

Return to Table of Contents

Object File Names

All class source files should match the name of the class and use a .cpp extension. Header files also match the class name and use .h extention.

For example:


            
            // Class source files and headers files are upper camel case.
            ClassName.cpp
            ClassName.h
          

Return to Table of Contents

Application File Names

The application file that contains the main method should have the same name as the directory (i.e. the executable), use the .cpp extension and be all lower case. The xml file should also have this name.

For example:


            
            // Application source files and xml files are lower case.
            applicationname.cpp
            applicationname.xml
          

Return to Table of Contents

#Includes

#Include Guards

Every object header file should begin with a #include guard to prevent double inclusions. That is, the first two lines should define the class macro with the #ifndef naming convention. The last line of the header file should close the guard with #endif .

For example:


            #ifndef ClassName_h
            #define ClassName_h
          

Return to Table of Contents

Ordering Library Includes

No code should exist before #include statements in ISIS 3 files. These #include statements should be separated into groups of libraries by a single blank line and each group should be ordered alphabetically. All #include statements for third party libraries (i.e. not in the ISIS namespace) should use angle brackets, not quotation marks.

For example:


             // Correct form 
            #include <cmath>

             // Incorrect form 
            #include "math.h"
          

The order of the groups are defined below:

  1. ISIS, IsisDebug and ThisClass header files.
  2. When needed, the Isis.h and IsisDebug.h should be the first includes. Next, for object *.cpp files, include the header for the class.
  3. C++ standard libraries.
  4. Examples include cstdlib, iostream, string, vector, map, cmath, and algorithm.
  5. Qt libraries
  6. Other third party groups can be listed in any order
  7. Examples include NAIF libraries, Boost, GNU Scientific Library (GSL), Geometry Engine Open Source (GEOS), and Google Protocol Buffers
  8. Other ISIS headers

Object Header Example:


            
            // The parent is always included in the header
            #include "ParentClass.h"
            
            // Some STL types are declared in the header
            #include <string>
            #include <vector>
            
            // Data member objects and objects used in inline functions
            // are included in the header
            #include "PvlGroup.h"
            #include "WorldMapper.h"

            namespace ISIS {
              class Displacement;
              class Pvl;
              ...
          

Object Implementation File Example:


            #include "IsisDebug.h"
            #include "ThisClass.h"

            #include <string>
            #include <vector>

            #include <QList>
            #include <QPair>

            #include <SpiceUser.h>

            #include "Constants.h"
            #include "Displacement.h"
            #include "IException.h"
            #include "Pvl.h"
            #include "WorldMapper.h"

            using namespace std;
            namespace ISIS {
              ...
          

Application Main File Example:


            #include "Isis.h"

            #include <map>

            #include "Application.h"
            #include "IException.h"
            #include "iString.h"
            #include "Process.h"
            #include "UserInterface.h"

            using namespace std;
            using namespace ISIS;
            void IsisMain() {
              ...
          

Return to Table of Contents

Forward Class Declarations

Forward class declarations are statements in a header file that let the compiler know that a class will be used in this file and will be defined later (when included in the implementation file). When appropriate, forward class declarations should be used in place of #include statements in a header file. This can minimize problems associated with include chains. Any function parameter, return value, pointer or reference can take a forward declaration. Here are some examples when the header file must have a #include rather than a forward class declaration:

Note that if a data member is declared as a pointer to avoid a #include statement in the header, then the copy constructor, assignment operator and destructor must be implemented.

Return to Table of Contents

Documentation

Documentation for ISIS 3 is done using Doxygen.

Return to Table of Contents

History Entries

Any time a method is added to a class, the header file class history should include an entry indicating this change with the name of the method indicated with empty parentheses.

Return to Table of Contents

Formatting

All history entries should be below an internal tag and indented 2 spaces from the start of the internal tag. Doxygen history entries in ISIS 3 should begin with the date of the form YYYY-MM-DD, followed by the name of the programmer(s) responsible for the changes. This is followed by a dash, padded by a space on each side before the comment. When wrapping a Doxygen history entry, the subsequent lines should begin 4 spaces after the first name of the first programmer submitting the change. This will make history entries easier to read.

For example:


            
            /**
             *
             * @internal
             *   @history 2011-01-01 Mickey Mouse - Original version.
             *   @history 2011-01-02 Mickey Mouse and Donald Duck - Added new
             *                           method, SetKeyword()
             */
          

Return to Table of Contents

Author Tag

The Doxygen author tag is required for class documentation and optional for method documentation.

For example:


            
            /**
             *
             * @author 2011-01-01 Mickey Mouse
             *
             * @internal
             *   @history 2011-01-01 Mickey Mouse - Original version.
             *   @history 2011-01-02 Mickey Mouse and Donald Duck - Added new
             *                           method, SetKeyword()
             */
          

Return to Table of Contents

Makefile Comments

Every Makefile for an application test or category test should have a comment on top explaining the purpose of the test case.

For example:


            # Test for bandnorm with default parameters:
            #         AVERAGE=BAND
            APPNAME = bandnorm

            include $(ISISROOT)/make/isismake.tsts

            commands:
                              $(APPNAME) from=$(INPUT)/f348b26.cub \
                              to=$(OUTPUT)/bandnormTruth.cub > /dev/null;
          

Return to Table of Contents

Source Code

Structures

The struct keyword is not all together disallowed in ISIS 3, however there are restrictions on its use. The use of a structure is prohibited from the public API in ISIS 3, this would include global definitions in a header file. That is, any structures in a class must be private or protected. Structures can also be used in applications. A structure that contains only data is acceptable in ISIS 3. Structures in ISIS 3 cannot have methods.

Return to Table of Contents

Implementation Files

Using statements should be placed in the implementation files after #include statements.

Return to Table of Contents

Support Class Files

With the exception of inner (or nested) classes, all classes should be contained within their own files. Each class should be split into two files, header and implementation file, unless it is proven that it is faster to inline all functions. Support classes are object files and so must have the name of the contained class. Also, the name of support classes should reflect the application or object that it supports.

For example:


            
            // Inside VimsCamera object directory.  Notice the Vims prefix on
            // this class name so that there is no danger of using an existing
            // class name from another camera model that has a sky map.
            VimsSkyMap.cpp
            
            // Inside cnetref application directory.
            CnetRefByEmission.cpp
          

Return to Table of Contents

Header Files

In general, header files should only include prototypes and declarations. Functions should not be implemented in the header file unless it is necessary or proven faster.

Using statements should not be used in header files.

Return to Table of Contents

Inline Member Functions

The inline keyword should only be used if a function is implemented in the header. Therefore, inline functions are only used when necessary or proven faster.

Return to Table of Contents

const Keyword

The const keyword should be used on any function that does not change the value of data members of the class. If necessary, an identical overridden version of the method should be written without the const keyword.

Return to Table of Contents

Declaring & Initializing Variables

Local Variable Declarations

It is recommended that just in time declaration is used for local variables whenever possible.

Return to Table of Contents

Initializing Variables

Primitive variable types should be initialized using an equal sign, not parentheses.

For example:


              // Initialize primitives with = sign.
              int i = 0;

              // Incorrect form - Do not initialize
              // primitive with parentheses.
              int i(0);
            

All class members should be initialized in the class constructor. Pointers must be initialized to NULL before they are set to any other value, especially before use of the keyword new and must be set back to NULL after they are deleted.

For example:


            ClassName::ClassName() {
              m_pointerVariable = NULL;
              if (condition) {
                m_pointerVariable = new OtherClass();
              }
              else {
                m_pointerVariable = new ThirdClass();
              }
            }

            ClassName::~ClassName() {
              delete m_pointerVariable;
              m_pointerVariable = NULL;
            }
          

Return to Table of Contents

Method Order in Implementation File

The methods in the *.cpp file should be ordered as the author finds logical. New methods added to a class should attempt to follow the same ordering. Some common styles of format are

  1. In the same order as the header file.
  2. Ordered by usage, where private methods are often listed directly after the public methods that call them.

Return to Table of Contents

Strings

IString

Instantiating the IString class is no longer recommended. This class may be given a couple of static methods that operate with QStrings in the future, but for all other purposes consider IString to be deprecated. IString should never be in the public API of new code.

Return to Table of Contents

QString

The QString class does most of what "iString" used to do for us. QString is the string we should always expect in our public API, with any conversions for the purposes with interfacing with other APIs to be done inside of the methods which interact with the other APIs. Please use QString wherever possible and reasonable. This was motivated by the following:

Return to Table of Contents

std::string

The STL string class doesn't provide an easy to use, intuitive interface for our purposes (parsing methods are global functions and cryptic, no unicode support without going to std::wstring, no arg(), split()/join(), tr(), etc... available). Many APIs expect std::string or const char * as input. If your class is interfacing with one of these APIs, please have your class take QStrings as arguments and convert to a std::string with QString::toStdString(). If you need to convert to a const char *, you can also use QString().toLatin1().data().

Return to Table of Contents

Other Strings

Other string classes should be handled like we're handing std::string, but a function may be created in the IString file to convert to the new type. For example, if there was a "somelib::AString" class, providing: somelib::AString toAString(QString) in IString.h is okay.

Return to Table of Contents

TO DO


Document History

Jeannie Backer2012-01-30 Original version
Jeannie Backer2012-02-23 Clarified the language for Member Function Names. Fixed typos.
Jeannie Backer2012-04-16 Replaced references to iException with IException due to class name change.
Jeannie Backer2012-04-19 changed line length limit from 80 to 100 columns.
Steven Lambright and Stuart Sides2012-07-31 Added Pointers and References under formatting
Steven Lambright2012-10-10 Added Strings section
JP Bonn2017-02-21 Incorporated sections of former Style Guide