-
1.1. General Principles
1.2 File Formatting
-
2.1. Naming Conventions
2.2 Do's and Don'ts
“Programs are meant to be read by humans and only incidentally for computers to execute.”
- H. Abelson and G. Sussman in Structure and Interpretation of Computer Programs
The purpose of this styleguide is to give a clear framework for other contributors, to minimize ambiguity, and to have a consistent way to convey the intent of code.
- Prefer clarity over brevity
- Don’t optimize prematurely
- In cases of ambiguity, use your best judgement
Source code files should adhere to the following:
- Encoded in UTF-8
- Use tabs for indentation
- Use LF for end-of-line sequences
- No trailing whitespace (Lines which end in spaces or tabs)
- Any
#includedirectives should be at the top of the file - Any header files have the
.hppfile extension - Any implementation files have the
.cppfile extension - Code should be within the
OpenVicnamespace (or a nested namespace) - Any submodules or third-party utilities should be in the
OpenVic/extension/depsdirectory - Groups of related source files should be kept in a sub-directory of
OpenVic/extension/src - Any lines that are longer than 120 characters in length should be split across multiple lines
| Item | Writing Convention | Example |
|---|---|---|
| Class names | Pascal Case | MyCoolExample |
| Struct names | Pascal Case | MyCoolExample |
| Variable and Attribute names | Camel Case | myCoolExample |
| Function and Method names | Camel Case | myCoolExample |
| Constants | Macro Case | MY_COOL_EXAMPLE |
| Macros | Macro Case | MY_COOL_EXAMPLE |
| Class or container type aliases | Pascal Case | MyCoolExample |
| Builtin or numeric type aliases | Camel Case ( _t suffix) |
myCoolExample_t |
| Enum names | Pascal Case | MyCoolExample |
| Enum values | Pascal Case | MyCoolExample |
-
Keep the opening scope brace on the same line
//Correct if (condition) { //Cool things here } //Incorrect if (condition) { //cool things here }
-
With arithmetic, relational, and logical operators keep spaces between variables and literals
//Correct int myNumber = (someVariable + 10) % 3; //Incorrect int myNumber=(someVariable+10)%3;
-
Prefix and postfix operators should be immediately attached to the affected variable
//Correct for (int x = 0; x < 10; x++) { //Something cool } //Incorrect for (int x = 0; x < 10; x ++ ) { //Something cool }
-
The content of classes should appear in the following order:
- Type Aliases
- Static (class-wide) attributes
- Attributes
- Constructors and Destructors
- Static (class-wide) methods
- Methods
class Human { public: using name_t = std::string; private: static size_t numberOfHumans; public: name_t name; size_t age; size_t familyMembers; Human(); ~Human(); static bool isMoreHumansThan(size_t number); private: void coolPrivateMethod(); public: void coolPublicMethod(); void anotherCoolPublicMethod(); inline bool isVotingAge() const { return age >= 18; } };
-
Class visibility specifiers should be followed by the next declaration on a new line at the same indentation level
- Group methods and attributes by their visibility specifier from most to least restrictive (
private,protected, thenpublic)
class ExampleClass { //Attributes... private: void firstPrivateMethod(); void secondPrivateMethod(); void thirdPrivateMethod(); protected: void firstProtectedMethod(); void secondProtectedMethod(); void thirdProtectedMethod(); public: void firstPublicMethod(); void secondPublicMethod(); void thirdPublicMethod(); };
- Group methods and attributes by their visibility specifier from most to least restrictive (
-
Methods which do not mutate an object's state should be marked as a
constmethod//Correct bool RGBColour::isColourBlack() const { return redChannel == 0 && greenChannel == 0 && blueChannel == 0; } //Incorrect bool RGBColour::isColourBlack() { return redChannel == 0 && greenChannel == 0 && blueChannel == 0; }
-
When argument or parameter lists are too long to easily fit on one line: begin the argument list on the next line, two indentation levels higher than the function's indentation.
//Correct callingAFunctionWithAVeryLongNameAndManyArguments( longArgumentNameOne, longArgumentNameTwo, longArgumentNameThree, longArgumentNameFour, longArgumentNameFive, longArgumentNameSix, longArgumentNameSeven, longArgumentNameEight); //Incorrect callingAFunctionWithAVeryLongNameAndManyArguments(longArgumentNameOne, longArgumentNameTwo, longArgumentNameThree, longArgumentNameFour, longArgumentNameFive, longArgumentNameSix, longArgumentNameSeven, longArgumentNameEight);
-
In header files, put
#pragma onceat the top of the file, not C-style header guards//Correct #pragma once /* header contents here */ //Incorrect #ifndef MY_COOL_HEADER_H #define MY_COOL_HEADER_H /* header contents here */ #endif
-
Use enum classes, not plain enums
//Correct enum class Colours { Red, Green, Blue, CharcoalGrey }; //Incorrect enum Colours { Red, Green, Blue, CharcoalGrey };
-
Use type aliases, not
typedefs//Correct using MyContainer = std::vector<int>; using byte_t = unsigned char; //Incorrect typedef std::vector<int> MyContainer; typedef unsigned char byte_t;
-
Use explicit types, do not use
auto//Correct std::pair<int, int> coordinate = getPlayerLocation(); //Incorrect auto coordinate = getPlayerLocation();
-
Do not use C-style casts, instead use C++ casts (ie:
static_cast,const_cast,reinterpret_cast)dynamic_castshould only be used with caution
//Correct int myNumber = static_cast<int>(someFloatValue); //Incorrect int myNumber = (int) someFloatValue;
-
When declaring a pointer, put the asterisk immediately after the type, followed by a space and the variable name
//Correct int* myPointer = &myNumber; //Incorrect int * myPointer = &myNumber; int *myPointer = &myNumber; int*myPointer = &myNumber;
-
Do not declare multiple pointer variables on a single line
//Correct int* p1; int* p2; //Incorrect int *p1, *p2;
-
Keep the initialization of a variable and its declaration as close as possible, ideally on the same line.
//Correct int myNumber = 23; //Incorrect int myNumber; myNumber = 23;
-
For constant values that are computable at compile-time, use
constexprinstead of theconstkeyword//Correct constexpr size_t UNIQUE_RGB_COLOURS = 256 * 256 * 256; //Incorrect const size_t UNIQUE_RGB_COLOURS = 256 * 256 * 256;
-
The name of functions returning a boolean value should start with
isorhas; whichever makes the most sense.//Correct bool isEven(int num) { return num % 2 == 0; } //Incorrect bool even(int num) { return num % 2 == 0; }
-
When a function parameter is being passed by const reference, put one space between the type and
const&. If a parameter is passed by mutable reference do not put a space between the type and the&//Correct for a const reference bool hasLargeNumber(std::vector<int> const& numbers) { //some cool stuff return true; } //Incorrect for a const reference bool hasLargeNumber(std::vector<int>const& numbers) { //some cool stuff return true; } //Correct for a mutable reference bool hasLargeNumber(std::vector<int>& numbers) { //some cool stuff return true; } //Incorrect for a mutable reference bool hasLargeNumber(std::vector<int> & numbers) { //some cool stuff return true; }
-
The include order should be: C++ standard headers, followed by Godot headers, then OpenVic headers
- C++ standard headers and Godot headers should be enclosed by angle brackets
<> - OpenVic headers should be enclosed by double quotes
""
//Correct #include <vector> #include <string> #include <godot_cpp/classes/object.hpp> #include <godot_cpp/core/class_db.hpp> #include "openvic/src/SampleHeader.hpp" #include "openvic/src/SampleHeader2.hpp" //Incorrect #include "openvic/src/SampleHeader.hpp" #include <godot_cpp/classes/object.hpp> #include "openvic/src/SampleHeader2.hpp" #include <godot_cpp/core/class_db.hpp> #include <vector> #include <string>
- C++ standard headers and Godot headers should be enclosed by angle brackets