blob: aacae6f3d7ee6667dd2a7c579af74e6444d65411 [file] [log] [blame] [view]
---
layout: page
title: CPP Code Style
nav_order: 4
parent: Developer Overview
---
# Gluten CPP Core Guidelines
This is a set of CPP core guidelines for Gluten. The aim is to make the codebase
simpler, more efficient, more maintainable by promoting consistency and according
to best practices.
## Philosophy
Philosophical rules are generally not measurable. However, they are valuable. For
Gluten CPP coding, there are a few Philosophical rules as the following.
* Write in ISO Standard C++.
* Standard API first, the CPP programming APIs are priority to system calls.
* Write code consistently. It's good for understanding and maintaining.
* Keep simple, making code clear and easy to read.
* Optimize code for reader, not for writer. Thus, more time will be spent reading
code than writing it.
* Make it work, and then make it better or faster.
* Don't import any complexity if possible. Collaborate with minimal knowledge
consensus.
## Code Formatting
Many aspects of C++ coding style will be covered by clang-format, such as spacing,
line width, indentation and ordering (for includes, using directives and etc).
* Always ensure your code is compatible with clang-format-15 for Velox backend.
* `dev/formatcppcode.sh` is provided for formatting Velox CPP code.
To format cmake files like CMakeLists.txt & *.cmake, `cmake-format` is required to
be installed. Here is an example.
```
apt install python3-pip -y
pip3 install --user cmake-format
cmake-format --first-comment-is-literal True --in-place cpp/velox/CMakeLists.txt
```
## Naming Conventions
* Use **PascalCase** for types (class, struct, enum, type alias, type
template parameter) and file name.
* Use **camelCase** for function, member and local variable, and non-type
template parameter.
* Use **camelCase_** for private and protected member variable.
* Use **snake_case** for namespace name and build target.
* Use **UPPER_SNAKE_CASE** for macro.
* Use **kPascalCase** for static constant and enumerator.
## Designs
* No over design.
* No negation of negation, `isValid` is better than `isNotInvalid`.
* Avoid corner case, and common case first.
* Express ideas directly, don't let me think.
* Make a check for the arguments in the interface between modules, and don't make a check
in the inner implementation, use `assert` in the private implementation instead of too
much safe check.
## Source File & Header File
* All header files must have a single-inclusion guard using `#pragma once`
* Always use `.h` as header file suffix, not `.hpp`.
* Always use `.cc` as source file suffix, neither `.cpp` nor `.cxx`.
* One file should contain one main class, and the file name should be consistent with
the main class name.
* Obvious exception: files used for defining various misc functions.
* If a header file has a corresponding source file, they should have the same file
name with different suffix, such as `a.h vs a.cc`.
* If a function is declared in the file `a.h`, ensure it's defined in the corresponding
source file `a.cc`, do not define it in other files.
* No deep source directory for CPP files, not do it as JAVA.
* Include header files should satisfy the following rules.
* Include the necessary header files, which means the source file (.cc) containing
the only one line `#include "test.h"` can be compiled successfully without
including any other header files.
* Do not include any unnecessary header files, the more including, the slower
compiling.
* In one word, no more, no less, just as needed.
## Class
* Base class name doesn't end with Base, use `Backend` instead of `BackendBase`.
* Ensure one class does one thing, and follows the single responsibility principle.
* No big class, No huge class, No too much interfaces.
* Distinguish interface from implementation, make implementations private.
* When designing a class hierarchy, distinguish between interface inheritance
and implementation inheritance.
* Ensure that public inheritance represent the relation of `is-a`.
* Ensure that private inheritance represent the relation of `implements-with`.
* Don't make a function `virtual` without reason.
* Ensure the polymorphic base class has a `virtual` destructor.
* Use `override` to make overriding explicit and to make the compiler work.
* Use `const` to mark the member function read-only as far as possible.
* When you try to define a `copy constructor` or a `operator=` for a class, remember
the `Rule of three/five/zero`.
## Function
* Make functions short and simple.
* Calling a meaningful function is more readable than writing too many statements
in place, but the performance-sensitive code path is an exception.
* Give the function a good name, how to check whether the function name is good
or not.
* When you read it loudly, you feel smooth.
* The information can be represented by arguments should not be encoded into
the function name. such as. use `get(size_t index)` instead of `getByIndex`.
* A function should focus on a single logic operation.
* A function should do as the name meaning.
* do everything covered by the function name
* don't do anything not covered by the function name
## Variable
* Make variable names simple and meaningful.
* Don't group all your variables at the top of the scope, it's an outdated habit.
* Declare variables as close to the usage point as possible.
## Constant
* Prefer const variables to using preprocessor (`#define`) to define constant values.
* Always use nullptr if you need a constant that represents a null pointer (T* for some T);
use 0 otherwise for a zero value.
## Macro
* Macros downgrade readability, break mind, and affect debug.
* Macros have side effects.
* Use macros cautiously and carefully.
* Consider using `const` variables or `inline` functions to replace macros.
* Consider defining macros with the wrap of `do {...} while (0)`
* Avoid using 3rd party library macros directly.
## Namespace
* Don't `using namespace xxx` in header files. Instead, you can do this in source files.
But it's still not encouraged.
* Place all Gluten CPP codes under `namespace gluten` because one level namespace
is enough. No nested namespace. Nested namespaces bring mess.
* The anonymous namespace is recommended for defining file level classes, functions
and variables. It's used to place file scoped static functions and variables.
## Resource Management
* Use handles and RAII to manage resources automatically.
* Immediately give the result of an explicit resource allocation to a manager
object.
* Prefer scoped objects and stack objects.
* Use raw pointers to denote individual objects.
* Use `pointer + size_t` to denote array objects if you don't want to use containers.
* A raw pointer (a `T*`) is non-owning.
* A raw reference (a `T&`) is non-owning.
* Understand the difference of `unique_ptr`, `shared_ptr`, `weak_ptr`.
* `unique_ptr` represents ownership, but not share ownership. `unique_ptr` is
equivalent to RAII, release the resource when the object is destructed.
* `shared_ptr` represents shared ownership by use-count. It is more expensive
that `unique_ptr`.
* `weak_ptr` models temporary ownership. It is useful in breaking reference cycles
formed by objects managed by `shared_ptr`.
* Use `unique_ptr` or `shared_ptr` to represent ownership.
* Prefer `unique_ptr` over `shared_ptr` unless you need to share ownership.
* Use `make_unique` to make `unique_ptr`s.
* Use `make_shared` to make `shared_ptr`s.
* Take smart pointers as parameters only to explicitly express lifetime semantics.
* **For general use**, take `T*` or `T&` arguments rather than smart pointers.
## Exception
* The exception specifications are changing always. The difference between various CPP
standards is big, so we should use exception cautiously in Gluten.
* Prefer `return code` to throwing exceptions.
* Prefer compile-time checking to run-time checking.
* Encapsulate messy constructors, rather than spreading through the code.
## Code Comment
* Add necessary comments. The comment is not the more the better, also not the
less the better.
* Good comment makes obscure code easily understood. It's unnecessary to add comments for
quite obvious code.
## References
* [CppCoreGuidelines](https://github.com/fluz/CppCoreGuidelines)
* [Velox CODING_STYLE](https://github.com/facebookincubator/velox/blob/main/CODING_STYLE.md)
* Thanks Gluten developers for their wise suggestions and helps.