Coding guidelines

Language and libraries

  • The codebase is mostly written in “C with classes”, a simple and unsophisticated subset of C++.
  • We use C++98.
  • We don’t use exceptions.
  • We mostly avoid templates.
  • We avoid inheritance, except “interface” inheritance.
  • We avoid operators, overloading, and default arguments.
  • We avoid using the preprocessor.
  • We don’t use STL (the algorithms-and-containers part of the C++ standard library).
  • We don’t use third-party utility libraries like Boost.
  • We maintain our own minimal utility library (roc_core) designed to be very lightweight and allowing fine-grained memory management.

Portability

  • The code should run on a variety of operating systems, compilers, and hardware architectures, including rather old compilers and distributions. See supported platforms page.
  • The code specific to platform, compiler, or optional features and dependencies, should be isolated inside corresponding target directories. All other code should be portable across all supported configurations.

Best practices

  • The code should compile without warnings (use --enable-werror SCons option).
  • Cover every component with class-level unit tests if possible. Additionally, cover high-level features with pipeline-level integration tests. We use CppUTest.
  • Prefer RAII and smart pointers for resource management.
  • Prefer either non-copyable or trivial-copy objects. Avoid making “heavy” operations implicit, in particular, operations involving memory management.
  • Use const when it is useful.
  • Use anonymous namespaces instead of static globals, functions, and constants.
  • Use enums instead of defines, when possible.
  • Use allocators and pools for memory management.
  • Log (using roc_log) important events and information needed to understand why an error occurred.
  • Panic (using roc_panic) when a contract or an invariant is broken. A panic is always preferred over a crash. However, remember that panics are only for bugs in Roc itself. Never panic on invalid or unexpected data from the outside world.

Coding style

  • The code should be formatted using scons fmt, which invokes clang-format. If it goes awry, you can prevent a file from being formatted by adding it to .fmtignore.
  • Header and source files should contain the “Roc authors” copyright and license header. Running scons fmt will automatically insert them.
  • Headers, classes, public members, and free functions should be documented using Doxygen. If Doxygen is installed, it is invoked during build and warns about undocumented items.
  • Prefer creating individual .h and .cpp files for every class. Use snake_case for file names and old-style header guards, which are automatically inserted by scons fmt.
  • Use upper case SNAKE_CASE for macros, CamelCase for class names, and lower case snake_case for methods, functions, fields, and variables. Add trailing underscore_ for private methods and fields.
  • The code should be formatted according to our 1TBS-like indentation style defined in .clang-format config:
    • use 4 spaces for indentation;
    • place opening braces on the same line as the control statement;
    • use braces even for single-statement blocks;
    • don’t place condition or loop bodies at the same line as the control statement.
  • #endif and #else statements should have trailing // <NAME> and // !<NAME> comments. Namespace closing brace should have trailing // namespace <name> comment.