]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/coding-style.md
import 15.2.0 Octopus source
[ceph.git] / ceph / src / seastar / coding-style.md
1 # Seastar Coding Style
2
3 ## Files
4
5 Header files have the `.hh` extension, source files use the `.cc` extension. All files must have a license and copyright blurb. Use `#pragma once` instead of an include guard.
6
7 Header files which contain a public part of the interface of Seastar go in the `include` directory. Internal header and source files which are private to the implementation go in the `src` directory.
8
9 ## Whitespace
10
11 Use spaces only; NEVER tabs. Rationale: tabs render differently on each system.
12
13 An _indent_ is four spaces. A double indent is eight spaces, a half-indent is two spaces.
14
15 ## Naming
16
17 We follow the C++ and Boost naming conventions: class names, variables, and functions are `words_separated_by_whitespace`.
18
19 Private data members are prefixed by an underscore:
20
21 ```c++
22 class my_class {
23 int _a_member;
24 public:
25 void foo() {
26 _a_member = 3;
27 }
28 };
29 ```
30
31 Think of the leading underscore as a shorthand for `this->`.
32
33 Template parameters and concepts use `CamelCase`
34
35 ## Including header files
36
37 In any file, to include a public header file (one in the `include` directory), use an absolute path with `<>` like this:
38
39 ```c++
40 #include <seastar/core/future.hh>
41 ```
42
43 In any private file, to include a private header file (one in the `src` directory), use an absolute path with `""` like this:
44
45 ```c++
46 #include "core/future_impl.hh"
47 ```
48
49 ## Braced blocks
50
51 All nested scopes are braced, even when the language allows omitting the braces (such as an if-statement), this makes patches simpler and is more consistent. The opening brace is merged with the line that opens the scope (class definition, function definition, if statement, etc.) and the body is indented.
52
53 ```c++
54 void a_function() {
55 if (some condition) {
56 stmt;
57 } else {
58 stmt;
59 }
60 }
61 ```
62
63 An exception is namespaces -- the body is _not_ indented, to prevent files that are almost 100% whitespace left margin.
64
65 When making a change, if you need to insert an indentation level, you can temporarily break the rules by insering a half-indent, so that the patch is easily reviewable:
66
67 ```c++
68 void a_function() {
69 while (something) { // new line - half indent
70 if (some condition) {
71 stmt;
72 } else {
73 stmt;
74 }
75 } // new line
76 }
77 ```
78
79 A follow-up patch can restore the indents without any functional changes.
80
81 ## Function parameters
82
83 Avoid output parameters; use return values instead. In/out parameters are tricky, but in some cases they are relatively standard, such as serialization/deserialization.
84
85 If a function accepts a lambda or an `std::function`, make it the last argument, so that it can be easily provided inline:
86
87 ```c++
88 template <typename Func>
89 void function_accepting_a_lambda(int a, int b, Func func);
90
91 int f() {
92 return function_accepting_a_lambda(2, 3, [] (int x, int y) {
93 return x + y;
94 });
95 }
96 ```
97
98 ## Complex return types
99
100 If a function returns a complicated return type, put its return type on a separate line, otherwise it becomes hard to see where the return type ends and where the function name begins:
101
102 ```c++
103 template <typename T1, T2>
104 template <typename T3, T4>
105 std::vector<typename a_struct<T1, T2>::some_nested_class<T3, T4>> // I'm the return type
106 a_struct<T1, T2>::a_function(T3 a, T4 b) { // And I'm the function name
107 // ...
108 }
109 ```
110
111 ## Whitespace around operators
112
113 Whitespace around operators should match their precedence: high precedence = no spaces, low precedency = add spaces:
114
115 ```c++
116 return *a + *b; // good
117 return * a+* b; // bad
118 ```
119
120 `if`, `while`, `return` (and `template`) are not function calls, so they get a space after the keyword.
121
122 ## Long lines
123
124 If a line becomes excessively long (>120 characters?), or is just complicated, break it into two or more lines. The second (and succeeding lines) are _continuation lines_, and have a double indent:
125
126 ```c++
127 if ((some_condition && some_other_condition)
128 || (more complicated stuff here...) // continuation line, double indent
129 || (even more complicated stuff)) { // another continuation line
130 do_something(); // back to single indent
131 }
132 ```
133
134 Of course, long lines or complex conditions may indicate that refactoring is in order.
135
136 ## Generic lambdas and types
137
138 Generic lambdas (`[] (auto param)`) are discouraged where the type is known. Generic
139 lambdas reduce the compiler's and other tools' ability to reason about the code.
140 In case the actual type of `param` doesn't match the programmers expectations,
141 the compiler will only detect an error in the lambda body, or perhaps
142 even lower down the stack if more generic functions are called. In the case of an
143 IDE, most of its functionality is disabled in a generic lambda, since it can't
144 assume anything about that parameter.
145
146 Of course, when there is a need to support multiple types, genericity is the correct
147 tool. Even then, type parameters should be constrained with concepts, in order to
148 catch type mismatches early rather than deep in the instantiation chain.
149
150