File: CONTRIBUTING.md

package info (click to toggle)
actor-framework 0.17.6-3.2
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 9,008 kB
  • sloc: cpp: 77,684; sh: 674; python: 309; makefile: 13
file content (477 lines) | stat: -rw-r--r-- 12,563 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
This document specifies how to contribute code to CAF.

Git Workflow
============

Please adhere to the following Git naming and commit message conventions.
Having a consistent work flow and style reduces friction and makes organizing
contributions a lot easier for all sides.

Branches
--------

- Our main branch is `master`. It reflects the latest development changes for
  the next release and should always compile. Nightly versions use the
  `master`. Users looking for a production-ready state are encouraged to use
  the latest release version instead.

- Push trivial bugfixes (e.g. typos, missing includes, etc.) consisting of a
  single commit directly to `master`. Otherwise, implement your changes in a
  topic or bugfix branch and file a pull request on GitHub.

- Implement new features and non-trivial changes in a *topic branch* with
  naming convention `topic/short-description`.

- Implement fixes for existing issues in a *bugfix branch* with naming
  convention `issue/$num`, where `$num` is the issue ID on GitHub.

- Simply use a fork of CAF if you are an external contributor.

Pull Requests
-------------

Check the following steps to prepare for a merge into `master` after completing
work in a topic or bugfix branch (or fork).

- Squash your commits into a single one if necessary. Each commit should
  represent a coherent set of changes.

- Wait for a code review and the test results of our CI.

- Address any review feedback and fix all issues reported by the CI.

- A maintainer will merge the pull request when all issues are resolved.

Commit Message Style
--------------------

- Summarize the changes in no more than 50 characters in the first line.
  Capitalize and write in an imperative present tense, e.g., "Fix bug" as
  opposed to "Fixes bug" or "Fixed bug".

- Suppress the dot at the end of the first line. Think of it as the header of
  the following description.

- Leave the second line empty.

- Optionally add a long description written in full sentences beginning on the
  third line. Indent at 72 characters per line.

Coding Style
============

When contributing source code, please adhere to the following coding style,
which is loosely based on the [Google C++ Style
Guide](https://google.github.io/styleguide/cppguide.html) and the coding
conventions used by the C++ Standard Library.

Example for the Impatient
-------------------------

```c++
// libcaf_example/caf/example/my_class.hpp

#pragma once

#include <string>

// use "//" for regular comments and "///" for doxygen

namespace caf {
namespace example {

/// This class is only being used as style guide example.
class my_class {
public:
  /// Brief description. More description. Note that CAF uses the
  /// "JavaDoc-style" autobrief option, i.e., everything up until the
  /// first dot is the brief description.
  my_class();

  /// Destructs `my_class`. Please use Markdown in comments.
  ~my_class();

  // suppress redundant @return if you start the brief description with "Returns"
  /// Returns the name of this instance.
  inline const std::string& name() const noexcept {
    return name_;
  }

  /// Sets the name of this instance.
  inline void name(const std::string& new_name) {
    name_ = new_name;
  }

  /// Prints the name to `std::cout`.
  void print_name() const;

  /// Does something (maybe).
  void do_something();

  /// Does something else but is guaranteed to never throw.
  void do_something_else() noexcept;

private:
  std::string name_;
};

} // namespace example
} // namespace caf
```

```c++
// libcaf_example/src/example/my_class.cpp

#include "caf/example/my_class.hpp"

#include <iostream>

namespace caf {
namespace example {

namespace {

constexpr const char default_name[] = "my object";

} // namespace

my_class::my_class() : name_(default_name) {
  // nop
}

my_class::~my_class() {
  // nop
}

void my_class::print_name() const {
  std::cout << name() << std::endl;
}

void my_class::do_something() {
  if (name() == default_name) {
    std::cout << "You didn't gave me a proper name, so I "
              << "refuse to do something."
              << std::endl;
  } else {
    std::cout << "You gave me the name \"" << name()
              << "\"... Do you really think I'm willing to do something "
                 "for you after insulting me like that?"
              << std::endl;
  }
}

void my_class::do_something_else() noexcept {
  // Do nothing if we don't have a name.
  if (name().empty())
    return;
  switch (name.front()) {
    case 'a':
      // handle a
      break;
    case 'b':
      // handle b
      break;
    default:
      handle_default();
  }
}

} // namespace example
} // namespace caf
```

```c++
// libcaf_example/test/example/my_class.cpp

#define CAF_SUITE example.my_class    // name of this test suite

#include "caf/example/my_class.hpp"   // header-under-test

#include "caf/test/dsl.hpp"           // caf::test includes

#include <iostream>                   // standard includes

// ...                                // other CAF includes

namespace {

struct fixture {};

} // namespace

CAF_TEST_FIXTURE_SCOPE(my_class_tests, fixture)

// ... any number of CAF_TEST ...

CAF_TEST_FIXTURE_SCOPE_END()
```

General
-------

- Use 2 spaces per indentation level.

- Use at most 80 characters per line.

- Never use tabs.

- Never use C-style casts.

- Never declare more than one variable per line.

- Only separate functions with vertical whitespaces and use comments to
  document logical blocks inside functions.

- Use `.hpp` as suffix for header files and `.cpp` as suffix for implementation
  files.

- Bind `*` and `&` to the *type*, e.g., `const std::string& arg`.

- Never increase the indentation level for namespaces and access modifiers.

- Use the order `public`, `protected`, and then `private` in classes.

- Always use `auto` to declare a variable unless you cannot initialize it
  immediately or if you actually want a type conversion. In the latter case,
  provide a comment why this conversion is necessary.

- Never use unwrapped, manual resource management such as `new` and `delete`.

- Prefer `using T = X` over `typedef X T`.

- Insert a whitespaces after keywords: `if (...)`, `template <...>`,
  `while (...)`, etc.

- Put opening braces on the same line:

  ```c++
  void foo() {
    // ...
  }
  ```

- Use standard order for readability: C standard libraries, C++ standard
  libraries, OS-specific headers (usually guarded by `ifdef`), other libraries,
  and finally (your) CAF headers. Include `caf/config.hpp` before the standard
  headers if you need to include platform-dependent headers. Use angle brackets
  for system includes and doublequotes otherwise.

  ```c++
  // example.hpp

  #include <vector>

  #include <sys/types.h>

  #include "3rd/party.h"

  #include "caf/fwd.hpp"
  ```

  Put the implemented header always first in a `.cpp` file.

  ```c++
  // example.cpp

  #include "caf/example.hpp" // header for this .cpp file

  #include "caf/config.hpp" // needed for #ifdef guards

  #include <algorithm>

  #ifdef CAF_WINDOWS
  #include <windows.h>
  #else
  #include <sys/socket.h>
  #endif

  #include "some/other/library.h"

  #include "caf/actor.hpp"
  ```

- Put output parameters in functions before input parameters if unavoidable.
  This follows the parameter order from the STL.

- Protect single-argument constructors with `explicit` to avoid implicit
  conversions.

- Use `noexcept` whenever it makes sense and as long as it does not limit future
  design space. Move construction and assignment are natural candidates for
  `noexcept`.

Naming
------

- All names except macros and template parameters should be
  lower case and delimited by underscores.

- Template parameter names should be written in CamelCase.

- Types and variables should be nouns, while functions performing an action
  should be "command" verbs. Classes used to implement metaprogramming
  functions also should use verbs, e.g., `remove_const`.

- Private and protected member variables use the suffix `_` while getter *and*
  setter functions use the name without suffix:

  ```c++
  class person {
  public:
    person(std::string name) : name_(std::move(name)) {
      // nop
    }

    const std::string& name() const {
      return name_
    }

    void name(const std::string& new_name) {
      name_ = new_name;
    }

  private:
    std::string name_;
  };
  ```

- Use `T` for generic, unconstrained template parameters and `x`
  for generic function arguments. Suffix both with `s` for
  template parameter packs and lists:

  ```c++
  template <class... Ts>
  void print(const Ts&... xs) {
    // ...
  }

  void print(const std::vector<T>& xs) {
    // ...
  }
  ```

Headers
-------

- Each `.cpp` file has an associated `.hpp` file.
  Exceptions to this rule are unit tests and `main.cpp` files.

- Each class has its own pair of header and implementation files and the
  relative path for the files are derived from the full class name. For
  example, the header file for `caf::example::my_class` of `libcaf_example` is
  located at `libcaf_example/caf/example/my_class.hpp` and the source file at
  `libcaf_example/src/example/my_class.cpp`.

- All header files use `#pragma once` to prevent multiple inclusion.

- Do not `#include` when a forward declaration suffices.

- Each library component must provide a `fwd.hpp` header providing forward
  declarations for all types used in the user API.

- Each library component should provide an `all.hpp` header that contains the
  main page for the documentation and includes all headers for the user API.

- Use `inline` for small functions (rule of thumb: 10 lines or less).

Breaking Statements
-------------------

- Break constructor initializers after the comma, use two spaces for
  indentation, and place each initializer on its own line (unless you don't
  need to break at all):

  ```c++
  my_class::my_class()
    : my_base_class(some_function()),
      greeting_("Hello there! This is my_class!"),
      some_bool_flag_(false) {
    // ok
  }
  other_class::other_class() : name_("tommy"), buddy_("michael") {
    // ok
  }
  ```

- Break function arguments after the comma for both declaration and invocation:

  ```c++
  intptr_t channel::compare(const abstract_channel* lhs,
                            const abstract_channel* rhs) {
    // ...
  }
  ```

- Break before tenary operators and before binary operators:

  ```c++
  if (today_is_a_sunny_day()
      && it_is_not_too_hot_to_go_swimming()) {
    // ...
  }
  ```

Template Metaprogramming
------------------------

Despite its power, template metaprogramming came to the language pretty
much by accident. Templates were never meant to be used for compile-time
algorithms and type transformations. This is why C++ punishes metaprogramming
with an insane amount of syntax noise. In CAF, we make excessive use of
templates. To keep the code readable despite all the syntax noise, we have some
extra rules for formatting metaprogramming code.

- Break `using name = ...` statements always directly after `=` if it
  does not fit in one line.

- Consider the *semantics* of a metaprogramming function. For example,
  `std::conditional` is an if-then-else construct. Hence, place the if-clause
  on its own line and do the same for the two cases.

- Use one level of indentation per "open" template and place the closing `>`,
  `>::type` or `>::value` on its own line. For example:

  ```c++
  using optional_result_type =
    typename std::conditional<
      std::is_same<result_type, void>::value,
      bool,
      optional<result_type>
    >::type;
  // think of it as the following (not valid C++):
  auto optional_result_type =
    conditional {
      if   result_type == void
      then bool
      else optional<result_type>
    };
  ```

- Note that this is not necessary when simply defining a type alias.
  When dealing with "ordinary" templates, indenting based on the position of
  the opening `<` is ok, e.g.:

  ```c++
  using response_handle_type = response_handle<Subtype, message,
                                               ResponseHandleTag>;
  ```

Preprocessor Macros
-------------------

- Use macros if and only if you can't get the same result by using inline
  functions or proper constants.

- Macro names use the form `CAF_<COMPONENT>_<NAME>`.

Comments
--------

- Start Doxygen comments with `///`.

- Use Markdown instead of Doxygen formatters.

- Use `@cmd` rather than `\cmd`.

- Use `//` to define basic comments that should not be processed by Doxygen.