|
| 1 | +# C++ Ethereum Coding Style |
| 2 | + |
| 3 | +## Code Formatting |
| 4 | + |
| 5 | +Use clang-format tool to format your changes, see [CONTRIBUTING](CONTRIBUTING.md) for details. |
| 6 | + |
| 7 | + |
| 8 | +## Namespaces |
| 9 | + |
| 10 | +1. No "using namespace" declarations in header files. |
| 11 | +2. All symbols should be declared in a namespace except for final applications. |
| 12 | +3. Preprocessor symbols should be prefixed with the namespace in all-caps and an underscore. |
| 13 | + |
| 14 | + // WRONG: |
| 15 | + #include <cassert> |
| 16 | + using namespace std; |
| 17 | + tuple<float, float> meanAndSigma(vector<float> const& _v); |
| 18 | + |
| 19 | + // CORRECT: |
| 20 | + #include <cassert> |
| 21 | + std::tuple<float, float> meanAndSigma(std::vector<float> const& _v); |
| 22 | + |
| 23 | + |
| 24 | +## Preprocessor |
| 25 | + |
| 26 | +1. File comment is always at top, and includes: |
| 27 | + - Copyright. |
| 28 | + - License. |
| 29 | + |
| 30 | +2. Never use #ifdef/#define/#endif file guards. Prefer #pragma once as first line below file comment. |
| 31 | +3. Prefer static const variable to value macros. |
| 32 | +4. Prefer inline constexpr functions to function macros. |
| 33 | + |
| 34 | + |
| 35 | +## Capitalization |
| 36 | + |
| 37 | +GOLDEN RULE: Preprocessor: ALL_CAPS; C++: camelCase. |
| 38 | + |
| 39 | +1. Use camelCase for splitting words in names, except where obviously extending STL/boost functionality in which case follow those naming conventions. |
| 40 | +2. The following entities' first alpha is upper case: |
| 41 | + - Type names. |
| 42 | + - Template parameters. |
| 43 | + - Enum members. |
| 44 | + - static const variables that form an external API. |
| 45 | +3. All preprocessor symbols (macros, macro arguments) in full uppercase with underscore word separation. |
| 46 | + |
| 47 | + |
| 48 | +All other entities' first alpha is lower case. |
| 49 | + |
| 50 | + |
| 51 | +## Variable prefixes |
| 52 | + |
| 53 | +1. Leading underscore `_` to parameter names. |
| 54 | + - Exception: `o_parameterName` when it is used exclusively for output. |
| 55 | + See also Declarations.6. |
| 56 | + - Exception: `io_parameterName` when it is used for both input and output. |
| 57 | + See also Declarations.6. |
| 58 | +2. Leading `c_` to const variables (unless part of an external API). |
| 59 | +3. Leading `g_` to global (non-const) variables. |
| 60 | +4. Leading `s_` to static (non-const, non-global) variables. |
| 61 | + |
| 62 | + |
| 63 | + |
| 64 | +## Error reporting |
| 65 | + |
| 66 | +Prefer exception to bool/int return type. |
| 67 | + |
| 68 | + |
| 69 | +## Declarations |
| 70 | + |
| 71 | +1. {Typename} + {qualifiers} + {name}. (**TODO**: Against [NL.26](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#nl26-use-conventional-const-notation)) |
| 72 | +2. Only one per line. |
| 73 | +3. Favour declarations close to use; don't habitually declare at top of scope ala C. |
| 74 | +4. Always pass non-trivial parameters with a const& suffix. |
| 75 | +5. To return multiple "out" values, prefer returning a tuple or struct. |
| 76 | + See [F.21]. |
| 77 | +6. Never use a macro where adequate non-preprocessor C++ can be written. |
| 78 | +7. Make use of auto whenever type is clear or unimportant: |
| 79 | + - Always avoid doubly-stating the type. |
| 80 | + - Use to avoid vast and unimportant type declarations. |
| 81 | + - However, avoid using auto where type is not immediately obvious from the context, and especially not for arithmetic expressions. |
| 82 | +8. Don't pass bools: prefer enumerations instead. |
| 83 | +9. Prefer enum class to straight enum. |
| 84 | + |
| 85 | + // WRONG: |
| 86 | + const double d = 0; |
| 87 | + int i, j; |
| 88 | + char *s; |
| 89 | + float meanAndSigma(std::vector<float> _v, float* _sigma, bool _approximate); |
| 90 | + Derived* x(dynamic_cast<Derived*>(base)); |
| 91 | + for (map<ComplexTypeOne, ComplexTypeTwo>::iterator i = l.begin(); i != l.end(); ++l) {} |
| 92 | + |
| 93 | + // CORRECT: |
| 94 | + enum class Accuracy |
| 95 | + { |
| 96 | + Approximate, |
| 97 | + Exact |
| 98 | + }; |
| 99 | + double const d = 0; |
| 100 | + int i; |
| 101 | + int j; |
| 102 | + char* s; |
| 103 | + std::tuple<float, float> meanAndSigma(std::vector<float> const& _v, Accuracy _a); |
| 104 | + auto x = dynamic_cast<Derived*>(base); |
| 105 | + for (auto i = x.begin(); i != x.end(); ++i) {} |
| 106 | + |
| 107 | + |
| 108 | +## Structs & classes |
| 109 | + |
| 110 | +1. Structs to be used when all members public and no virtual functions. |
| 111 | + - In this case, members should be named naturally and not prefixed with 'm_' |
| 112 | +2. Classes to be used in all other circumstances. |
| 113 | + |
| 114 | + |
| 115 | + |
| 116 | +## Members |
| 117 | + |
| 118 | +1. One member per line only. |
| 119 | +2. Private, non-static, non-const fields prefixed with m_. |
| 120 | +3. Avoid public fields, except in structs. |
| 121 | +4. Use override, final and const as much as possible. |
| 122 | +5. No implementations with the class declaration, except: |
| 123 | + - template or force-inline method (though prefer implementation at bottom of header file). |
| 124 | + - one-line implementation (in which case include it in same line as declaration). |
| 125 | +6. For a property 'foo' |
| 126 | + - Member: m_foo; |
| 127 | + - Getter: foo(); also: for booleans, isFoo() |
| 128 | + - Setter: setFoo(); |
| 129 | + |
| 130 | + |
| 131 | +## Naming |
| 132 | + |
| 133 | +1. Collection conventions: |
| 134 | + - ~s means `std::vector` e.g. `using MyTypes = std::vector<MyType>` |
| 135 | + - ~Set means `std::set` e.g. `using MyTypeSet = std::set<MyType>` |
| 136 | + - ~Hash means `std::unordered_set` e.g. `using MyTypeHash = std::unordered_set<MyType>` |
| 137 | +2. Class conventions: |
| 138 | + - ~Face means the interface of some shared concept. (e.g. FooFace might be a pure virtual class.) |
| 139 | +3. Avoid unpronounceable names: |
| 140 | + - If you need to shorten a name favour a pronouncable slice of the original to a scattered set of consonants. |
| 141 | + - e.g. Manager shortens to Man rather than Mgr. |
| 142 | +4. Avoid prefixes of initials (e.g. DON'T use IMyInterface, CMyImplementation) |
| 143 | +5. Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments. |
| 144 | + - A dictionary and thesaurus are your friends. |
| 145 | + - Spell correctly. |
| 146 | + - Think carefully about the class's purpose. |
| 147 | + - Imagine it as an isolated component to try to decontextualise it when considering its name. |
| 148 | + - Don't be trapped into naming it (purely) in terms of its implementation. |
| 149 | + |
| 150 | + |
| 151 | + |
| 152 | +## Type-definitions |
| 153 | + |
| 154 | +1. Prefer `using` to `typedef`. E.g. `using ints = std::vector<int>` rather than |
| 155 | + `typedef std::vector<int> ints`. |
| 156 | +2. Generally avoid shortening a standard form that already includes all important information: |
| 157 | + - e.g. stick to `shared_ptr<X>` rather than shortening to `ptr<X>`. |
| 158 | +3. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently. |
| 159 | + - e.g. `using Guard = std::lock_guard<std::mutex>; ///< Guard is used throughout the codebase since it's clear in meaning and used commonly.` |
| 160 | +4. In general expressions should be roughly as important/semantically meaningful as the space they occupy. |
| 161 | + |
| 162 | + |
| 163 | + |
| 164 | +## Commenting |
| 165 | + |
| 166 | +1. Comments should be doxygen-compilable, using @notation rather than \notation. |
| 167 | +2. Document the interface, not the implementation. |
| 168 | + - Documentation should be able to remain completely unchanged, even if the method is reimplemented. |
| 169 | + - Comment in terms of the method properties and intended alteration to class state (or what aspects of the state it reports). |
| 170 | + - Be careful to scrutinise documentation that extends only to intended purpose and usage. |
| 171 | + - Reject documentation that is simply an English transaction of the implementation. |
| 172 | + |
| 173 | + |
| 174 | + |
| 175 | +## Logging |
| 176 | + |
| 177 | +Logging should be performed at appropriate verbosities depending on the logging message. |
| 178 | +The more likely a message is to repeat (and thus cause noise) the higher in verbosity it should be. |
| 179 | +Some rules to keep in mind: |
| 180 | + |
| 181 | + - Verbosity == 0 -> Reserved for important stuff that users must see and can understand. |
| 182 | + - Verbosity == 1 -> Reserved for stuff that users don't need to see but can understand. |
| 183 | + - Verbosity >= 2 -> Anything that is or might be displayed more than once every minute |
| 184 | + - Verbosity >= 3 -> Anything that only a developer would understand |
| 185 | + - Verbosity >= 4 -> Anything that is low-level (e.g. peer disconnects, timers being cancelled) |
| 186 | + |
| 187 | + |
| 188 | +## Recommended reading |
| 189 | + |
| 190 | +Herb Sutter and Bjarne Stroustrup |
| 191 | +- "C++ Core Guidelines" (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md) |
| 192 | + |
| 193 | +Herb Sutter and Andrei Alexandrescu |
| 194 | +- "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices" |
| 195 | + |
| 196 | +Scott Meyers |
| 197 | +- "Effective C++: 55 Specific Ways to Improve Your Programs and Designs (3rd Edition)" |
| 198 | +- "More Effective C++: 35 New Ways to Improve Your Programs and Designs" |
| 199 | +- "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14" |
| 200 | + |
| 201 | + |
| 202 | +[F.21]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#f21-to-return-multiple-out-values-prefer-returning-a-tuple-or-struct |
0 commit comments