diff options
author | chriseth <chris@ethereum.org> | 2018-03-13 19:42:21 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-13 19:42:21 +0800 |
commit | f56afa21c4c30be51541d99027b96058227da6c4 (patch) | |
tree | ad11f80c8f3938428d01bf2cf2fcc823c55dce07 /CODING_STYLE.md | |
parent | 6055bc250fb393cf621f6c7e63a2d89b880fe3a6 (diff) | |
download | dexon-solidity-f56afa21c4c30be51541d99027b96058227da6c4.tar.gz dexon-solidity-f56afa21c4c30be51541d99027b96058227da6c4.tar.zst dexon-solidity-f56afa21c4c30be51541d99027b96058227da6c4.zip |
Update CODING_STYLE.md
Diffstat (limited to 'CODING_STYLE.md')
-rw-r--r-- | CODING_STYLE.md | 132 |
1 files changed, 70 insertions, 62 deletions
diff --git a/CODING_STYLE.md b/CODING_STYLE.md index ee924e72..2cc9ac70 100644 --- a/CODING_STYLE.md +++ b/CODING_STYLE.md @@ -3,20 +3,22 @@ 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. +- 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. -- If you have run-on lines, indent as you would for a block. b. Line widths: -- Don't worry about having lines of code > 80-char wide. +- 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. Don't use braces for condition-body one-liners. +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 first paren and keyword, but *not* following first paren or preceding final paren. -f. No spaces when fewer than intra-expression three parens together; when three or more, space according to clarity. -g. No spaces for subscripting or unary operators. -h. No space before ':' but one after it, except in the ternary operator: one on both sides. -i. Space all other operators. -j. Braces, when used, always have their own lines and are at same indentation level as "parent" scope. +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"); } @@ -25,6 +27,7 @@ foo->bar(someLongVariableName, 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]) @@ -36,6 +39,11 @@ foo->bar( 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; @@ -43,7 +51,8 @@ foo->bar( a. No "using namespace" declarations in header files. b. All symbols should be declared in a namespace except for final applications. -c. Preprocessor symbols should be prefixed with the namespace in all-caps and an underscore. +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> @@ -90,16 +99,16 @@ All other entities' first alpha is lower case. 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 "c_" to const variables (unless part of an external API). -c. Leading "g_" to global (non-const) variables. -d. Leading "s_" to static (non-const, non-global) variables. +b. Leading "g_" to global (non-const) variables. +c. Leading "s_" to static (non-const, non-global) variables. -5. Error reporting: - -- Prefer exception to bool/int return type. +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: @@ -108,15 +117,14 @@ 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. Always pass non-trivial parameters with a const& suffix. -f. If a function returns multiple values, use std::tuple (std::pair acceptable). Prefer not using */& arguments, except where efficiency requires. -g. Never use a macro where adequate non-preprocessor C++ can be written. -h. Make use of auto whenever type is clear or unimportant: -- Always avoid doubly-stating the type. -- Use to avoid vast and unimportant type declarations. -- However, avoid using auto where type is not immediately obvious from the context, and especially not for arithmetic expressions. -i. Don't pass bools: prefer enumerations instead. -j. Prefer enum class to straight enum. +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) @@ -134,13 +142,18 @@ enum class Accuracy Approximate, Exact }; +struct MeanSigma +{ + float mean; + float standardDeviation; +}; double const d = 0; int i; int j; char* s; -std::tuple<float, float> meanAndSigma(std::vector<float> const& _v, Accuracy _a); -auto x = dynamic_cast<Derived*>(base); -for (auto i = x.begin(); i != x.end(); ++i) {} +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 @@ -169,17 +182,10 @@ f. For a property 'foo' 9. Naming -a. Collection conventions: -- -s means std::vector e.g. using MyTypes = std::vector<MyType> -- -Set means std::set e.g. using MyTypeSet = std::set<MyType> -- -Hash means std::unordered_set e.g. using MyTypeHash = std::unordered_set<MyType> -b. Class conventions: -- -Face means the interface of some shared concept. (e.g. FooFace might be a pure virtual class.) -c. Avoid unpronouncable names; -- If you need to shorten a name favour a pronouncable slice of the original to a scattered set of consonants. -- e.g. Manager shortens to Man rather than Mgr. -d. Avoid prefixes of initials (e.g. DON'T use IMyInterface, CMyImplementation) -e. Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments. +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. @@ -194,8 +200,9 @@ a. Prefer 'using' to 'typedef'. e.g. using ints = std::vector<int>; rather than 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's clear in meaning and used commonly. +- 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. @@ -207,40 +214,41 @@ b. Document the interface, not the implementation. - 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 (libethereum -> libethcore -> libdevcrypto -> libdevcore -> boost -> STL). For example: +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. -#include <libethereum/Defaults.h> -#include <libdevcrypto/SHA3.h> -#include <libdevcore/Log.h> -#include <libdevcore/Exceptions.h> -#include <libdevcore/CommonData.h> -#include <libdevcore/Common.h> -#include <boost/filesystem.hpp> -#include <string> +Example: -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. +``` +#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> -13. Logging +#include <boost/range/adaptor/reversed.hpp> +#include <boost/algorithm/string/replace.hpp> -Logging should be performed at appropriate verbosities depending on the logging message. -The more likely a message is to repeat (and thus cause noise) the higher in verbosity it should be. -Some rules to keep in mind: +#include <utility> +#include <numeric> +``` - - Verbosity == 0 -> Reserved for important stuff that users must see and can understand. - - Verbosity == 1 -> Reserved for stuff that users don't need to see but can understand. - - Verbosity >= 2 -> Anything that is or might be displayed more than once every minute - - Verbosity >= 3 -> Anything that only a developer would understand - - Verbosity >= 4 -> Anything that is low-level (e.g. peer disconnects, timers being cancelled) +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. -14. Recommended reading +13. Recommended reading Herb Sutter and Bjarne Stroustrup - "C++ Core Guidelines" (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md) |