Coding Convention¶
This document specifies the coding conventions for the Shark library.
Most of the conventions are considered mandatory. A few optional rules are marked as such.
Naming Conventions¶
Class/Interface Names¶
All type names (classes, interfaces, enumerations) should use the InfixCaps style. Start with an upper-case letter, and capitalize the first letter of any subsequent word in the name, as well as any letters that are part of an acronym. All other characters in the name are lower-case. Do not use underscores to separate words. Class names should be nouns or noun phrases. Interface names depend on the salient purpose of the interface and are prefixed with a capitalized I. If the purpose is primarily to endow an object with a particular capability, then the name should be an adjective (ending in -able or -ible if possible) that describes the capability; e.g., ISearchable, ISortable, INetworkAccessible. Otherwise use nouns or noun phrases.
Member Names¶
Names of non-constant, non-pointer fields are prefixed with m_
and use the camelCase-style. Pointers that are owned by the class,
i.e. they are freed on destruction, are prefixed with mp_
and
use the camelCase-style. Pointers that are not owned by the class are
prefixed with mep_
.
m_
: Membermp_
: Member Pointer (optional rule)mep_
: Member External Pointer (optional rule)
Names of fields being used as constants should be all upper-case, with underscores separating words. The following are considered to be constants:
MIN_VALUE
MAX_BUFFER_SIZE
OPTIONS_FILE_NAME
One-character field names should be avoided except for temporary and looping variables. In these cases use (optional rule):
c
for a chard
d for a doublee
for an Exception objectf
for a floati
,j
,k
,m
,n
for integersp
,q
,r
,s
for strings
An exception is where a strong convention for the one-character name
exists, such as x
, y
, z
for coordinates.
Method Names¶
Method names should use the infixCaps style. Start with a lower-case letter, and capitalize the first letter of any subsequent word in the name, as well as any letters that are part of an acronym. All other characters in the name are lower-case. Do not use underscores to separate words. Method names should be imperative verbs or verb phrases, for example:
showStatus()
drawCircle()
addLayoutComponent()
A method to get or set some property or member of the class should be
called property()
or setProperty()
respectively, where
“property” is the name of the property.
A method to test some boolean property of the class should be called
isProperty()
, where “property” is the name of the property.
Formatting and White Space Usage¶
Blank Lines¶
Blank lines can improve readability by grouping sections of the code that are logically related. Blank lines should also be used in the following places:
- After the copyright block comment.
- Between class declarations.
- Between method declarations.
- Before a block or single-line comment, unless it is the first line in a block.
Indentation¶
Only tabulators should be used to indent lines, i.e., no space character should be part of the white space at the beginning of a line. The reasoning behind this convention is: (1) convenient tabulator characters are used for indentation, (2) code is well-aligned in any text editor, independent of the interpretation of tabulator characters, and (3) text further on in a line remains aliged as long as it does not spread beyond a single level of indentation. Example:
.___.___{
.___.___.___int a = 42;.......................................//.magic.answer
.___.___.___char q[] = "The.ultimate.question.of.life,."
.___.___.___..........."the.universe,.and.everything";........//.corresponding.question
.___.___}
Here, “.___” is used to indicate a tabulator, while a single dot “.” indicates a space character. Obviously, the code block will look pretty with different tabulator sizes in place, and the comments at the end of lines two and four remain aligned.
A single tabulator should be added at each indentation level. Usually curly braces indicate the next level of indentation, with the exception of namespaces.
Namespaces¶
All code in the Shark library is placed into the namespace shark
.
Currently, the only other namespace is shark::detail
. Content within
the detail namespace is considered ‘protected’, and it is often found in
files placed in ‘impl’ sub-directories. This code may be less
well-documented than the ‘public’ code base since it is not intended to
be used directly from outside the library.
Class Layout¶
A class definition should be structured as follows:
/// Documentation of the role of the class as a whole
class ClassName : public BaseClass {
public:
/// Documentation for the constructor, if necessary
ClassName();
~ClassName();
/// Documentation for property 1
PropertyType1 property1() const;
void setProperty1( const PropertyType1 & property );
/// Documentation for property 2
PropertyType2 & property2();
const PropertyType2 & property2() const;
void setProperty2();
/// Documentation for property 3
PropertyType3 * property3();
const PropertyType3 * property3() const;
void setProperty3();
/// Documentation for property 4
bool isProperty4() const;
void setProperty4( bool value );
protected:
/// Documentation for member m_property1
PropertyType1 m_property1;
/// Documentation for member m_property2
PropertyType2 m_property2;
/// Documentation for member m_property3
PropertyType3 * mp_property3();
/// Documentation for member m_property4
bool m_property4;
};
Interface Layout¶
An interface should only contain pure virtual methods and a virtual, empty destructor. No members should be put within an interface declaration. To reduce the effort to implement an interface, a general purpose default implementation can be provided in an abstract class that inherits the respective interface.
Header and Source Files¶
The general rule is that declarations should be put into header files and implementations should go into source files. There may be exceptions for declarations that are used only locally within one source file, such as in example files or unit test.
A declaration in the above sense is everything that does not directly generate code, while everything that has a direct imprint as executable code or data in the library is an implementation. Examples of declarations are:
- class declarations
- inline functions, including their implementations
- template classes and functions, including their implementations
Examples of implementations are
- bodies of non-template functions, free or members of a class
- static variables
All header files have to be protected against multiple inclusion by the following sequence of pre-processor statements:
#ifndef SHARK_<MODULE>_<FILENAME>_H
#define SHARK_<MODULE>_<FILENAME>_H
[...declarations...]
#endif
For example, the file Exception.h in the module Core is
protected by the name SHARK_CORE_EXCEPTION_H
.
Shark makes extensive use of templates. Therefore large parts of the code base are found in header files. To maintain a clean structure some headers are ‘hidden’ in sub-directories with name impl.
Statements with strong side effects should be avoided in header files.
using
statements must not be used at global scope or the scope of
the shark namespace in header files. Definition of names by means of
#define
statements should be avoided where possible.
Unit Tests¶
When adding functionality to Shark it is mandatory to also add meaningful test cases.
Other tasks¶
It is one feature of the Shark tutorials that they list all Models, Kernels, Losses, Optimizers, StoppingCriteria, and Trainers implemented in Shark. These lists are one of the few components that do not update automatically via Sphinx-Doxygen-Code magic. Thus, if you add a new class implementing any of the above, please make this known in the corresponding list. Thank you!