CODING-GUIDELINES.md 11.7 KB
Newer Older
1 2
# Eris coding guidelines

3 4 5
This document covers the coding guidelines used in Eris code for consistency.
Not all classes currently conform to this, but all new code should aim to do
so.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

This document is neither exhaustive nor absolute.  Minor violations may be
acceptable if they have a good rationale behind them.

These guidelines are inspired by (but differ from) the [Google C++ Style
Guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml)

## Naming conventions for variables/classes/etc.

- Class names should start with a capital letter.  If consisting of multiple
  words, the first letter of each word should be capitalized with no underscore
  between words.  Example: `Awesome`, `MyClass`, but not `someClass` or
  `That_Class`.

- namespaces should be lower-case and usually in the `eris` namespace or a
  namespace nested within `eris` (e.g. `eris::firm`).

- Structs should always be declared in lower case with underscores separating
  words, such as `some_struct` or `blah`.

- Methods should start with a lower-case letter, with upper-case letters used
  to distinguish words and no underscores, such as `meth` or `myMethod`.

- Public member variables should be lower-case, with underscores separating
  words, such as `foo` or `some_value`.

- Private and protected member variables should be lower-case with underscores
  separating words, and followed by an underscore, such as `foo_` or
  `some_value_`.

36 37 38
- Local variables should generally be named in the same way as public member
  variables, but there is considerably more freedom since such variables are
  not part of the API.
39 40 41 42 43 44 45 46


## Directory and source filename structure

- Headers for C++ code use a .hpp extension.  Only if a header is pure C code
  may .h be used.

- Header file hierarchy should follow the C++ namespace hierarchy.  For
47 48
  example, class eris::ClassName belongs in `eris/ClassName.hpp`;
  eris::firm::Magical belongs in `eris/firm/Magical.hpp`.
49 50 51 52 53 54 55 56 57

- Headers for classes are generally stored in a header file with the same name
  as the class, such as `eris::ClassName` being defined in
  `eris/ClassName.hpp`.  Some exceptions for tightly related classes are
  acceptable: for example, `eris/Bundle.hpp` defines both `Bundle` and
  `BundleNegative` classes, while `eris/Firm.hpp` has both `Firm` and `FirmNoProd`
  classes.

- Header files beginning with a lower-case letter are used for collections of
58
  small classes or definitions.  For example, the `eris::id_t` typedef is
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
  defined in eris/types.hpp, and a few small algorithm functions and classes
  are in `eris/algorithms.hpp`.

- Source files associated with headers go under `src/eris`, and should have
  exactly the same name as the header file, but with a `.cpp` extension instead
  of `.hpp`.  (`.c` is acceptable for pure-C classes).


## Documentation

Eris uses doxygen for API documentation.  Rules to follow when adding doxygen
documentation:

- Every public and protected member should be documented in its `.hpp` file
  with doxygen-compatible comments.

75 76 77 78
- Documentation comments should be useful enough for someone to understand the
  interface and purpose of a function or variable (for public members), and
  useful enough for a subclass writer to make use of the member (for protected
  members).
79 80 81 82 83 84 85 86 87 88 89 90 91

- Multi-line comments should be formatted using `/** ... */` comments, in the
  following style:

      /** Comment starts here and
       * continues here.
       *
       * More comments.
       *
       * \param blah description of parameter
       */
      void foo(int blah);

92 93
- Single-line documentation comments may use either `/** ... */` comments, or
  `/// ...` comments. `/// ...` should *not* be used for multi-line comments.
94 95 96

- Mathematical equations (as opposed to computational equations) should be in
  LaTeX using [doxygen's MathJax
97 98
  interface](http://www.stack.nl/~dimitri/doxygen/manual/formulas.html) whenever
  such notation is helpful.  For example, \f$\pi = 3.1415\hdots\f$.
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113

- Namespaces should be documented in an appropriate and logical place.  If
  classes in a given namespace typically have a common base class, the base
  class header should contain the namespace documentation (for example,
  `eris/Firm.hpp` documents the `eris::firm` namespace).

- All documentation should be in the .hpp header files.  The .cpp source files
  should contain code comments as needed to help in following the source code,
  but *documentation* belongs in the header files.


## General code guidelines

### Headers
- Every header should begin with `#pragma once` (rather than an explicit
114
  include guard definition).
115 116 117 118 119 120

- Eris library code should use angle-bracket includes rather than quoted
  includes, i.e. `#include <path/name.hpp>` instead of `#include
  "path/name.hpp"`.

- Use inline functions/methods only when they are small and frequently called,
121
  and have relatively simple logic, or are otherwise required (e.g. for
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
  templated classes or methods)

- Use as few `#include`s as is practical.  Consider using forward declarations
  of classes when feasible (and definitely do so to avoid cyclical
  dependencies).  `#include`s in a header should only be used for code needed
  in the header itself; if the include is only needed for the `.cpp` source
  code, the include belongs in the `.cpp` file.

### Scoping
- Use the narrowest scope possible.  That is, avoid declaring all local
  variables at the top of a function/method/block: instead declare local
  variables as needed in the code.

- Initialize variables during declaration, where feasible.  For example, prefer
  `int answer = 42;` to `int magic; magic = 42;`

### Classes
- Minimize work in constructors.

- Single-argument constructors should usually be declared explicit, to avoid
  implicit type conversion.  If a single-argument constructor is purposely not
  explicit (for example, wrapper classes or copy constructors), it should be
  (briefly) documented.

- Classes should always be declared with the `class` operator; a `struct`
  should only be used as a passive container.

- Avoid private inheritance.  Usually private inheritance is better served by
  storing the private class instance as a private member object instead.
  Exceptions should be carefully noted (for instance, the `eris::noncopyable`
  class is explicitly designed to be privately inherited).

- Don't use operator overloading unless such overloading is reasonably obvious
  and natural to users of the class.  Bundle uses it extensively, since
  operations like adding two bundles together makes immediate sense.  Most
  classes don't have such a natural interpretation.

- Default method parameters are acceptable.  If the default value is a non-zero
  numeric value and is likely to be used by an inheriting class, expose the
  default using a constexpr variable with at least as much scope as the method
  it is used in (i.e.  public for public methods, public or protected for
  protected methods).  For example:

      public:
          static constexpr double default_foo = 3.0;
          virtual void doSomething(double foo = default_foo);

169
  Don't bother with a `constexpr`, however, when the default is boolean,
170 171 172 173 174 175 176 177 178 179 180 181 182
  nullptr, or similar.

- Overridden methods should have an explicit "override" identifier,
  particularly to make it easier to update if the base class arguments need to
  change in some way.

### Argument passing
- In general, pass simple types by value, and pass complex types by const
  reference, unless otherwise justified.

### C++ language features
- Eris is C++11 code; all standard C++11 features are acceptable and
  encouraged.
183

184 185
- use `auto` to avoid pointlessly cluttered type names (especially for
  templated type names).
186

187 188 189 190 191 192 193 194 195 196 197 198
- Avoid direct use of pointers as much as possible, preferring
  `std::shared_ptr`, `std::unique_ptr`, etc.

## Code formatting

- 4-space indent.  No tabs.

- Aim for 100-character wide code.  Some code may exceed this, slightly, if
  wrapping would be ugly.  Documentation comments should always be wrapped at
  100 characters (because any decent editor makes this easy), unless strictly
  needed (for example, for a code example).

199 200 201 202 203
- Opening braces (`{`) following unwrapped lines should be at the end of a
  line.  If the opening brace follows a wrapped declaration (for example, a
  complicated method declaration or if statement), the brace may be at the end
  of the last line or on a new line; in the latter case the brace should not be
  indented.
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

- Closing braces should line up with the first character that started the
  block, if on their own line, and on the same line as the opening brace, if
  not.  For example:
      if (blah) {
          ...
      }
      else if (something complicated that
          requires wrapping)
      { ... }
      else { ... }

- Don't "cuddle" elses: the 'else' keyword should start the line.

- Prefer spaces around operators and comparisons, e.g. `a + b` and `a == b`
  rather than `a+b` and `a==b`, unless doing so is pointlessly verbose.

- Pad the outside, not the inside, of parentheses (EXCEPT for parentheses used
  for a function call, see below).  e.g. `(a + b) * 3` and `if (a >= b) { ...
  }` rather than `( a + b )*3` or `if(a >= b) { ... }` or `if (a >= b){ ... }`.

- Don't-pad-inside takes precedence for nested parentheses, e.g. `((a + b) *
  3)` should be used instead of `( (a + b) * 3)`.

- Never put a space between a function call and the opening parenthesis for its
  arguments.  e.g. `func(a, b)`, not `func (a, b)`.
  - There is one exception to this with operator methods: both `operator=(...)`
    and `operator = (...)` should be considered acceptable: the former follows
    this rule, the latter follows the "space-around-operators-and-comparisons"
    rule, above).

- No spaces around pointer and reference expressions.  e.g. `*p`, `&r`,
  `p->a`, `r.a`.

- Declarations of pointers and references should attach the `*` or `&` to the
  variable, not the type.  e.g. `char *c` not `char* c`.  This is particularly
  important when declaring multiple variables, since the prohibited `char* a,
  b, c` would declare b and c as chars, rather than `char*`'s.

- Functions or methods returning references or pointers should disregard the
  previous rule: that is, write `int& foo() { ... }` instead of `int &foo() {
  ... }`.

- Function/method arguments should either be all on one line, or listed one per
  line, indented, beginning on a new line.  (Both rules may be followed at
  once: all may be on the same line following the method name).  For multi-line
  function declarations, the closing parenthesis may be on the same line as the
  last argument, or on its own line, lined up with either the arguments or the
  opening declaration.  e.g.

      bool f1(int a, double b, double c) {

      bool f2(
          int a, double b, double c) {

      bool f3(
          int a,
          double b,
          double c) {

      bool f4(
          int a,
          double b,
          double c
          ) {
      
      bool f5(
          int a, double b, double c
      ) {

  are all acceptable, while the following are not:

      bool f5(
          int a, double b,
          double c) {

      bool f6(
      int a,
      double b,
      double c) {

- Do not indent code contained by namespaces.

- When all the code in a file is inside a nested namespace, declare the
  namespace on one line and similarly close the namespace on one line with
  multiple closing brackets (spaces between the brackets are optional).  For
  example:
  
      namespace top { namespace nested {
      
      ...
      
      }}
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311

- The public:/protected:/private: keyword may be outdended, such as:

      class SomeClass {
      public:
          SomeClass();
          void someMethod();

  This is not, however, required: the following is also acceptable:

      class SomeClass {
          public:
              SomeClass();
              void someMethod();