diff options
Diffstat (limited to 'CODING_STYLE.md')
-rw-r--r-- | CODING_STYLE.md | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/CODING_STYLE.md b/CODING_STYLE.md new file mode 100644 index 00000000..2cc9ac70 --- /dev/null +++ b/CODING_STYLE.md @@ -0,0 +1,262 @@ +0. Formatting + +GOLDEN RULE: Follow the style of the existing code when you make changes. + +a. Use tabs for leading indentation +- tab stops are every 4 characters (only relevant for line length). +- One indentation level -> exactly one byte (i.e. a tab character) in the source file. +b. Line widths: +- Lines should be at most 99 characters wide to make diff views readable and reduce merge conflicts. +- Lines of comments should be formatted according to ease of viewing, but simplicity is to be preferred over beauty. +c. Single-statement blocks should not have braces, unless required for clarity. +d. Never place condition bodies on same line as condition. +e. Space between keyword and opening parenthesis, but not following opening parenthesis or before final parenthesis. +f. No spaces for unary operators, `->` or `.`. +g. No space before ':' but one after it, except in the ternary operator: one on both sides. +h. Add spaces around all other operators. +i. Braces, when used, always have their own lines and are at same indentation level as "parent" scope. +j. If lines are broken, a list of elements enclosed with parentheses (of any kind) and separated by a + separator (of any kind) are formatted such that there is exactly one element per line, followed by + the separator, the opening parenthesis is on the first line, followed by a line break and the closing + parenthesis is on a line of its own (unindented). See example below. + +(WRONG) +if( a==b[ i ] ) { printf ("Hello\n"); } +foo->bar(someLongVariableName, + anotherLongVariableName, + anotherLongVariableName, + anotherLongVariableName, + anotherLongVariableName); +cout << "some very long string that contains completely irrelevant text that talks about this and that and contains the words \"lorem\" and \"ipsum\"" << endl; + +(RIGHT) +if (a == b[i]) + printf("Hello\n"); // NOTE spaces used instead of tab here for clarity - first byte should be '\t'. +foo->bar( + someLongVariableName, + anotherLongVariableName, + anotherLongVariableName, + anotherLongVariableName, + anotherLongVariableName +); +cout << + "some very long string that contains completely irrelevant " << + "text that talks about this and that and contains the words " << + "\"lorem\" and \"ipsum\"" << + endl; + + + +1. Namespaces; + +a. No "using namespace" declarations in header files. +b. All symbols should be declared in a namespace except for final applications. +c. Use anonymous namespaces for helpers whose scope is a cpp file only. +d. Preprocessor symbols should be prefixed with the namespace in all-caps and an underscore. + +(WRONG) +#include <cassert> +using namespace std; +tuple<float, float> meanAndSigma(vector<float> const& _v); + +(CORRECT) +#include <cassert> +std::tuple<float, float> meanAndSigma(std::vector<float> const& _v); + + + +2. Preprocessor; + +a. File comment is always at top, and includes: +- Copyright. +- License (e.g. see COPYING). +b. Never use #ifdef/#define/#endif file guards. Prefer #pragma once as first line below file comment. +c. Prefer static const variable to value macros. +d. Prefer inline constexpr functions to function macros. +e. Split complex macro on multiple lines with '\'. + + + +3. Capitalization; + +GOLDEN RULE: Preprocessor: ALL_CAPS; C++: camelCase. + +a. Use camelCase for splitting words in names, except where obviously extending STL/boost functionality in which case follow those naming conventions. +b. The following entities' first alpha is upper case: +- Type names. +- Template parameters. +- Enum members. +- static const variables that form an external API. +c. All preprocessor symbols (macros, macro arguments) in full uppercase with underscore word separation. + + +All other entities' first alpha is lower case. + + + +4. Variable prefixes: + +a. Leading underscore "_" to parameter names. +- Exception: "o_parameterName" when it is used exclusively for output. See 6(f). +- Exception: "io_parameterName" when it is used for both input and output. See 6(f). +b. Leading "g_" to global (non-const) variables. +c. Leading "s_" to static (non-const, non-global) variables. + + + +5. Assertions: + +- use `solAssert` and `solUnimplementedAssert` generously to check assumptions + that span across different parts of the code base, for example before dereferencing + a pointer. + + +6. Declarations: + +a. {Typename} + {qualifiers} + {name}. +b. Only one per line. +c. Associate */& with type, not variable (at ends with parser, but more readable, and safe if in conjunction with (b)). +d. Favour declarations close to use; don't habitually declare at top of scope ala C. +e. Pass non-trivial parameters as const reference, unless the data is to be copied into the function, then either pass by const reference or by value and use std::move. +f. If a function returns multiple values, use std::tuple (std::pair acceptable) or better introduce a struct type. Do not use */& arguments. +g. Use parameters of pointer type only if ``nullptr`` is a valid argument, use references otherwise. Often, ``boost::optional`` is better suited than a raw pointer. +h. Never use a macro where adequate non-preprocessor C++ can be written. +i. Only use ``auto`` if the type is very long and rather irrelevant. +j. Do not pass bools: prefer enumerations instead. +k. Prefer enum class to straight enum. +l. Always initialize POD variables, even if their value is overwritten later. + + +(WRONG) +const double d = 0; +int i, j; +char *s; +float meanAndSigma(std::vector<float> _v, float* _sigma, bool _approximate); +Derived* x(dynamic_cast<Derived*>(base)); +for (map<ComplexTypeOne, ComplexTypeTwo>::iterator i = l.begin(); i != l.end(); ++l) {} + + +(CORRECT) +enum class Accuracy +{ + Approximate, + Exact +}; +struct MeanSigma +{ + float mean; + float standardDeviation; +}; +double const d = 0; +int i; +int j; +char* s; +MeanAndSigma ms meanAndSigma(std::vector<float> const& _v, Accuracy _a); +Derived* x = dynamic_cast<Derived*>(base); +for (auto i = x->begin(); i != x->end(); ++i) {} + + +7. Structs & classes + +a. Structs to be used when all members public and no virtual functions. +- In this case, members should be named naturally and not prefixed with 'm_' +b. Classes to be used in all other circumstances. + + + +8. Members: + +a. One member per line only. +b. Private, non-static, non-const fields prefixed with m_. +c. Avoid public fields, except in structs. +d. Use override, final and const as much as possible. +e. No implementations with the class declaration, except: +- template or force-inline method (though prefer implementation at bottom of header file). +- one-line implementation (in which case include it in same line as declaration). +f. For a property 'foo' +- Member: m_foo; +- Getter: foo() [ also: for booleans, isFoo() ]; +- Setter: setFoo(); + + + +9. Naming + +a. Avoid unpronouncable names +b. Names should be shortened only if they are extremely common, but shortening should be generally avoided +c. Avoid prefixes of initials (e.g. do not use IMyInterface, CMyImplementation) +c. Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments. +- A dictionary and thesaurus are your friends. +- Spell correctly. +- Think carefully about the class's purpose. +- Imagine it as an isolated component to try to decontextualise it when considering its name. +- Don't be trapped into naming it (purely) in terms of its implementation. + + + +10. Type-definitions + +a. Prefer 'using' to 'typedef'. e.g. using ints = std::vector<int>; rather than typedef std::vector<int> ints; +b. Generally avoid shortening a standard form that already includes all important information: +- e.g. stick to shared_ptr<X> rather than shortening to ptr<X>. +c. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently. +- e.g. using Guard = std::lock_guard<std::mutex>; ///< Guard is used throughout the codebase since it is clear in meaning and used commonly. +d. In general expressions should be roughly as important/semantically meaningful as the space they occupy. +e. Avoid introducing aliases for types unless they are very complicated. Consider the number of items a brain can keep track of at the same time. + + + +11. Commenting + +a. Comments should be doxygen-compilable, using @notation rather than \notation. +b. Document the interface, not the implementation. +- Documentation should be able to remain completely unchanged, even if the method is reimplemented. +- Comment in terms of the method properties and intended alteration to class state (or what aspects of the state it reports). +- Be careful to scrutinise documentation that extends only to intended purpose and usage. +- Reject documentation that is simply an English transaction of the implementation. +c. Avoid in-code comments. Instead, try to extract blocks of functionality into functions. This often already eliminates the need for an in-code comment. + + +12. Include Headers + +Includes should go in increasing order of generality (libsolidity -> libevmasm -> libdevcore -> boost -> STL). +The corresponding .h file should be the first include in the respective .cpp file. +Insert empty lines between blocks of include files. + +Example: + +``` +#include <libsolidity/codegen/ExpressionCompiler.h> + +#include <libsolidity/ast/AST.h> +#include <libsolidity/codegen/CompilerContext.h> +#include <libsolidity/codegen/CompilerUtils.h> +#include <libsolidity/codegen/LValue.h> + +#include <libevmasm/GasMeter.h> + +#include <libdevcore/Common.h> +#include <libdevcore/SHA3.h> + +#include <boost/range/adaptor/reversed.hpp> +#include <boost/algorithm/string/replace.hpp> + +#include <utility> +#include <numeric> +``` + +See http://stackoverflow.com/questions/614302/c-header-order/614333#614333 for the reason: this makes it easier to find missing includes in header files. + + +13. Recommended reading + +Herb Sutter and Bjarne Stroustrup +- "C++ Core Guidelines" (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md) + +Herb Sutter and Andrei Alexandrescu +- "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices" + +Scott Meyers +- "Effective C++: 55 Specific Ways to Improve Your Programs and Designs (3rd Edition)" +- "More Effective C++: 35 New Ways to Improve Your Programs and Designs" +- "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14" |