Update CODING_STYLE.md

This commit is contained in:
chriseth 2018-03-13 12:42:21 +01:00 committed by GitHub
parent 6055bc250f
commit f56afa21c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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.
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 <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>
#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. Logging
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:
- 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)
14. Recommended reading
13. Recommended reading
Herb Sutter and Bjarne Stroustrup
- "C++ Core Guidelines" (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md)