Coding Style Guide

There are only two important rules:

    1. When making changes, conform to the style and conventions of the surrounding code.

    2. Strive for clarity, even if that means occasionally breaking the guidelines. Use your head and ask for advice if your common sense seems to disagree with the conventions.

Below we try to enumerate the guidelines embodied in the code.

File conventions

    • C++ implementation should be named "*.cpp". Headers should be named "*.h".

    • Header foo.h should have its contents surrounded by

#ifndef OPENIMAGEIO_FOO_H #define OPENIMAGEIO_FOO_H ... #endif // OPENIMAGEIO_FOO_H

    • All source files should begin with the copyright and license, which can be found in the LICENSE file (or cut and pasted from any other other source file). Two notes on this:

        • For NEW source files, please do change the copyright year to the present. DO NOT edit existing files only to update the copyright year, it just creates pointless deltas and offers no increased protection.

        • One or two files also credit NVIDIA. Do NOT copy that line to any new files, it really only applies to the small number of files where it already appears.

Line length

Each line of text in your code should be at most 80 characters long.

Generally the only exceptions are for comments with example commands or URLs - to make cut and paste easier.

The other exception is for those rare cases where letting a line be longer (and wrapping on an 80-character window) is actually a better and clearer alternative than trying to split it into two lines. Sometimes this happens, but it's extremely rare.

DO NOT alter somebody else's code to re-wrap lines (or change whitespace) just because you found something that violates the rules. Let the group/author/leader know, and resist the temptation to change it yourself.

Formatting

    • Indent 4 spaces at a time, and use actual spaces, not tabs. For files that must use tabs for some reason, tabs should always be on 8's. Most editors have a setting that forces indentations to be spaces. With emacs, you can do this:

(setq c-default-style "bsd") (setq-default indent-tabs-mode nil)

    • Opening brace on the same line as the condition or loop.

    • One statement per line, except in rare cases where violating this rule makes the code more clear.

    • Three (3) consecutive empty lines between function or class method implementations, one blank line between method declarations within a class definition. Put a single blank line within a function if it helps to visually separate different sequential tasks. Don't put multiple blank lines in a row within a function, or blank lines right after an opening brace or right before a closing brace. The goal is to use just enough white space to help developers visually parse the code (for example, spotting at a glance where new functions begin), but not so much as to spread it out or be confusing.

    • For if, for, while, etc., put a space before the paren, but NOT inside the parens. For example:

if (foo) // Yes if(foo) // No if ( foo ) // No

    • Function calls should have a space between the function name and the opening parenthesis, NO space inside the parenthesis, except for a single blank space between each argument. For example:

x = foo (a, b); // Yes, this is always ok x = foo ( a, b ); // No x = foo (a,b); // No x = foo(a, b); // No x = foo(a); // Occasionally, this just looks better, when the function name is short, // and there's just one very short argument. What can I say, I do it too.

    • Function declarations: function names should begin at column 0 for a full function definition. (It's ok to violate this rule for very short inline functions within class definitions.)

    • Here is a short code fragment that shows some of these rules in action:

static int function (int a, int b) { int x = a + b; if (a == 0 || b == 0) { x += 1; x *= 4; } else { x -= 3; } for (int i = 0; i < 3; ++i) { x += a * i; x *= foo (i); // function call } return x; }

    • Don't ever reformat, re-indent, change whitespace, or make any other such changes to working code. If you're adding just a few lines or fixing a bug in existing code, stick to the style of the surrounding code. In very rare circumstances, and with consensus of the group, reformatting is sometimes helpful to improve code readability, but it should be done as a separate formatting-only checkin.

Identifiers

    • In general, classes and templates should start with upper case and capitalize new words:

class CustomerList;

    • In general, local variables should start with lower case.

    • If your class is extremely similar to, or modeled after, something in the standard library, Boost, or something else we interoperate with, it's ok to use their naming conventions. For example, very general utility classes and templates (the kind of thing you would normally find in std or boost) should be lower case with underscores separating words, as they would be if they were standards.

template <class T> shared_ptr; class scoped_mutex;

    • Macros should be ALL_CAPS, if used at all.

    • Names of data should generally be nouns. Functions/methods are trickier: a the name of a function that returns a value but has no side effects should be a noun, but a procedure that performs an action should be a verb.

Class structure

    • Try to avoid public data members, although there are some classes that serve a role similar to a simple C struct -- a very straightforward collection of data members. In these, it's fine to make the data members public and have clients set and get them directly.

    • Private member data should be named m_foo (alternately, it's ok to use the common practice of member data foo_, but don't mix the conventions within a class).

    • Private member data that needs public accessors should use the convention:

void foo (const T& newfoo) { m_foo = newfoo; } const T& foo () const { return m_foo; }

    • Avoid multiple inheritance.

    • Namespaces: yes, use them!

Third-party libraries

    • Whenever applicable, use the following Boost libraries: Smart pointers, Filesystem, Foreach, Format, Random, Regex, Thread, Tokenizer, Unordered, uBLAS. Don't you dare write new code that duplicates the functionality of these excellent libraries, many of which are slated to become part of the next C++ standard.

    • Other Boost libraries are potentially ok, consult with the team first.

    • Please do use IlmBase vector, matrix, and utility classes where applicable. Don't write your own vector or matrix code!

    • Use these libraries for OIIO internals, but please DO NOT require them in any of our main external APIs unless it's been thoroughly discussed and approved by the group.

Comments and Doxygen

    • Prefer C++ comments (starting line with //) rather than C comments (/* ... */).

    • For any function that may be used by other programmers (e.g., public or protected members of classes), please use Doxygen-style comments. They looks like this:

/// Explanation of a class. Note THREE slashes! /// Also, you need at least two lines like this. If you don't have enough /// for two lines, make one line blank like this: /// class myclass { .... float foo; ///< Doxygen comments on same line look like this }

    • If you know Doxygen well, please feel free to use the various other markups.

    • But don't go so crazy with Doxygen markups that the comment itself, in an ordinary editor, is not as readable as possible. The Doxygen-generated pages are nice, but the place that needs to be most readable is in the code.

    • Comment philosophy: try to be clear, try to help teach the reader what's going on in your code.

    • Use FIXME comments for code that is temporary, a short-term solution, or good-enough but not perfect.

        • These should include the string FIXME in all caps, followed by your name, e-mail address, or other identifier in parentheses.

        • The main purpose is to have a consistent FIXME format searchable by the person adding the comment (who can provide more details upon request).

        • A FIXME is not a commitment to provide the fix yourself.

        • If your FIXME is of the form "At a future date do something" make sure that you either include a very specific date ("Fix by November 2005") or a very specific event ("Remove this code when all clients can handle XML responses.").

// FIXME(kl@gmail.com): Use a "*" here for concatenation operator. // FIXME(Zeke): change this to use relations.

[Based on Google's TODO comments]

Miscellaneous

    • Macros should be used only rarely -- prefer inline functions, templates, enums, or "const" values wherever possible.

Bottom Line

    • When in doubt, look elsewhere in the code base for examples of similar structures and try to format your code in the same manner.