coding_guidelines.rst (11570B)
1 .. default-role:: literal 2 3 PISM coding guidelines 4 ====================== 5 6 .. contents:: 7 8 File names 9 ---------- 10 11 C++ source files use the extension `.cc`. Headers use `.hh`. C code uses `.c` and `.h`. 12 13 The *basename* of a file containing the source code for a class should match the name of 14 this class, including capitalization. For example, a class `Foo` is declared in `Foo.hh` 15 and implemented in `Foo.cc`. 16 17 Source and header files 18 ----------------------- 19 20 Each header file must have an include guard. Do *not* use "randomized" names of include 21 guards. 22 23 Headers should *not* contain function and class method implementations unless these 24 implementations *should be inlined*; see below. 25 26 Inline functions and methods 27 ---------------------------- 28 29 Implementations of inline methods should be *outside* of class declarations and in a 30 *separate header* called `Foo_inline.hh`. This header will then be included from `Foo.hh`. 31 32 Including header files 33 ---------------------- 34 35 Include all system headers before PISM headers. Separate system headers from PISM headers 36 with an empty line. 37 38 Good: 39 40 .. code-block:: c++ 41 42 #include <cassert> 43 #include <cstring> 44 45 #include "IceGrid.hh" 46 47 Bad: 48 49 .. code-block:: c++ 50 51 #include <cstring> 52 #include "IceGrid.hh" 53 #include <cassert> 54 55 Whenever appropriate add comments explaining why a particular header was included. 56 57 .. code-block:: c++ 58 59 #include <cstring> // strcmp 60 61 Naming 62 ------ 63 64 Variable 65 ^^^^^^^^ 66 67 - Variable names should use lower case letters and (if necessary) digits separated by 68 underscores, for example: `ice_thickness`. 69 - Do not abbreviate names of variables used in more than one scope **unless** this is 70 needed to keep the name under 30 characters. If a function uses a variable so many times 71 typing a long name is a hassle, create a reference with a shorter name that is only 72 visible in this scope. (This alias will be compiled away.) 73 - Single-letter variable names should only be used in "small" scopes (short functions, 74 etc.) 75 - If you are going to use a single-letter name, pick a letter that is easy to read (avoid 76 `i`, `l`, and `o`). 77 - Names of class data members should use the `m_` prefix, for example: `m_name`. 78 - Names of static data members should use the `sm_` prefix. 79 - Global variables (which should be avoided in general) use the `g` prefix. 80 81 Types and classes 82 ^^^^^^^^^^^^^^^^^ 83 84 Names of types and classes use `CamelCase`. 85 86 Functions and class methods 87 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 88 89 Names of functions and class methods use the same rules are variable names, with some 90 additions. 91 92 - If a method is used to get a property of an object that cannot be reset (example: 93 `IceGrid::Mx()`), omit `get_` from the name. 94 - If a getter method has a corresponding setter method, their names should be 95 *predictable*: `Foo::get_bar()` and `Foo::set_bar()`. In this case, *do not* omit `get_` 96 from the name of the getter. 97 98 Namespaces 99 ---------- 100 101 Everything in PISM goes into the `pism` namespace. See the source code browser for more 102 namespaces (roughly one per sub-system). 103 104 Notable namespaces include: 105 106 - ``atmosphere`` 107 - ``bed`` 108 - ``calving`` 109 - ``energy`` 110 - ``frontalmelt`` 111 - ``hydrology`` 112 - ``ocean`` 113 - ``rheology`` 114 - ``sea_level`` 115 - ``stressbalance`` 116 - ``surface`` 117 118 Using directives and declarations 119 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 120 121 Do *not* import all names from a namespace with `using namespace foo;` 122 123 Do import *specific* names with `using ::foo::bar;` in `.cc` files. 124 125 126 Formatting 127 ---------- 128 129 PISM includes a `.clang-format` file that makes it easy to re-format source to make it 130 conform to these guidelines. 131 132 To re-format a file, commit it to the repository, then run 133 134 .. code-block:: none 135 136 clang-format -i filename.cc 137 138 (Here `-i` tells clang-format to edit files "in place." Note that editing in place is 139 safe because you added it to the repository.) 140 141 Logical operators should be surrounded by spaces 142 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 143 144 .. code-block:: c++ 145 146 // Good 147 if (a == b) { 148 action(); 149 } 150 151 // Bad 152 if (a==b) { 153 action(); 154 } 155 156 Commas and semicolons should be followed by a space 157 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 158 159 .. code-block:: c++ 160 161 // Good 162 function(a, b, c); 163 164 // Bad 165 function(a,b,c); 166 function(a,b ,c); 167 168 Binary arithmetic operators should be surrounded by spaces 169 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 170 171 .. code-block:: c++ 172 173 // Good 174 f = x + y / (z * w); 175 176 // Bad 177 f = x+y/(z*w); 178 179 Statements 180 ^^^^^^^^^^ 181 182 One statement per line. 183 184 .. code-block:: c++ 185 186 // Good 187 x = 0; 188 y = x + 1; 189 190 // Bad 191 x = 0; y = x + 1; 192 193 Code indentation 194 ^^^^^^^^^^^^^^^^ 195 196 - Use two spaces per indentation level. 197 - Do not use tabs. 198 - Opening braces go with the keyword ("One True Brace Style"). 199 200 Examples: 201 202 .. code-block:: c++ 203 204 int function(int arg) { 205 return 64; 206 } 207 208 for (...) { 209 something(); 210 } 211 212 class Object { 213 public: 214 Object(); 215 }; 216 217 Return statements 218 ^^^^^^^^^^^^^^^^^ 219 220 Return statements should appear on a line of their own. 221 222 Do not surround the return value with parenthesis if you don't have to. 223 224 .. code-block:: c++ 225 226 // Good 227 int function(int argument) { 228 if (argument != 0) { 229 return 64; 230 } 231 } 232 233 // Bad 234 int function(int argument) { 235 if (argument != 0) return(64); 236 } 237 238 239 Conditionals 240 ^^^^^^^^^^^^ 241 242 - one space between `if` and the opening parenthesis 243 - no spaces between `(` and the condition (`(condition)`, not `( condition )`) 244 - all `if` blocks should use braces (`{` and `}`) *unless* it makes the code significantly 245 harder to read 246 - `if (condition)` should always be on its own line 247 - the `else` should be on the same line as the closing parenthesis: `} else { ...` 248 249 .. code-block:: c++ 250 251 // Good 252 if (condition) { 253 action(); 254 } 255 256 // Bad 257 if (condition) action(); 258 259 // Sometimes acceptable: 260 if (condition) 261 action(); 262 263 Loops 264 ^^^^^ 265 266 `for`, `while`, `do {...} unless` loops are formatted similarly to conditional blocks. 267 268 .. code-block:: c++ 269 270 for (int k = 0; k < N; ++k) { 271 action(k); 272 } 273 274 while (condition) { 275 action(); 276 } 277 278 do { 279 action(); 280 } unless (condition); 281 282 Error handling 283 -------------- 284 285 First of all, PISM is written in C++, so unless we use a non-throwing `new` and completely 286 avoid STL, exceptions are something we have to live with. This means that we more or less 287 have to use exceptions to handle errors in PISM. (Mixing two error handling styles is a 288 *bad* idea.) 289 290 So, throw an exception to signal an error; PISM has a generic runtime error exception 291 class `pism::RuntimeError`. 292 293 To throw an exception with an informative message, use 294 295 .. code-block:: c++ 296 297 throw RuntimeError::formatted(PISM_ERROR_LOCATION, 298 "format string %s", "data"); 299 300 Error handling in a parallel program is hard. If all ranks in a communicator throw an 301 exception, that's fine. If some do and some don't PISM will hang as soon as one rank 302 performs a locking MPI call. I don't think we can prevent this in general, but we can 303 handle some cases. 304 305 Use 306 307 .. code-block:: c++ 308 309 ParallelSection rank0(communicator); 310 try { 311 if (rank == 0) { 312 // something that may throw 313 } 314 } catch (...) { 315 rank0.failed(); 316 } 317 rank0.check(); 318 319 to wrap code that is likely to fail on some (but not all) ranks. `rank0.failed()` prints 320 an error message from the rank that failed and `rank0.check()` calls `MPI_Allreduce(...)` 321 to tell other ranks in a communicator that everybody needs to throw an exception. 322 (`pism::ParallelSection::failed()` should be called in a `catch (...) {...}` block 323 **only**.) 324 325 In general one should not use `catch (...)`. It *should* be used in these three cases, 326 though: 327 328 1. With `pism::ParallelSection` (see above). 329 2. In callback functions passed to C libraries. (A callback is not allowed to throw, so we 330 have to catch everything.) 331 3. In `main()` to catch all exceptions before terminating. 332 333 Performing an action every time a PISM exception is thrown 334 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 335 336 The class `pism::RuntimeError` allows setting a "hook" that is called by the constructor 337 of `RuntimeError`. See the example below for a way to use it. 338 339 .. code-block:: c++ 340 341 #include <cstdio> 342 343 #include "error_handling.hh" 344 345 void hook(pism::RuntimeError *exception) { 346 printf("throwing exception \"%s\"\n", exception->what()); 347 } 348 349 int main(int argc, char **argv) { 350 351 MPI_Init(&argc, &argv); 352 353 pism::RuntimeError::set_hook(hook); 354 355 try { 356 throw pism::RuntimeError("oh no!"); 357 } catch (pism::RuntimeError &e) { 358 printf("caught an exception \"%s\"!\n", e.what()); 359 } 360 361 MPI_Finalize(); 362 363 return 0; 364 } 365 366 Calling C code 367 ^^^^^^^^^^^^^^ 368 369 Check the return code of every C call and convert it to an exception if needed. Use macros 370 `PISM_CHK` and `PISM_C_CHK` for this. 371 372 When calling several C function in sequence, it may make sense to wrap them in a function. 373 Then we can check its return value and throw an exception if necessary. 374 375 .. code-block:: c++ 376 377 int call_petsc() { 378 // Multiple PETSc calls here, followed by CHKERRQ(ierr). 379 // This way we need to convert *one* return code into an exception, not many. 380 return 0; 381 } 382 383 // elsewhere: 384 int err = call_petsc(); PISM_C_CHK(err, 0, "call_petsc"); 385 386 Use assert() for sanity-checks that should not be used in optimized code 387 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 388 389 The `assert` macro should be used to check pre-conditions and post-conditions that can 390 fail *due to programming errors*. 391 392 **Do not** use `assert` to validate user input. 393 394 Note that *user input includes function arguments* for all functions and public members of 395 classes accessible using Python wrappers. (Use exceptions instead.) 396 397 Function design 398 --------------- 399 400 Functions are the way to *manage complexity*. They are not just for code reuse: the main 401 benefit of creating a function is that a self-contained piece of code is easier both to 402 **understand** and **test**. 403 404 Functions should not have side effects (if at all possible). In particular, do not use and 405 especially do not *modify* "global" objects. If a function needs to modify an existing 406 field "in place", pass a reference to that field as an argument and document this argument 407 as an "input" or an "input/output" argument. 408 409 Function arguments; constness 410 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 411 412 Pass C++ class instances by const reference *unless* an instance is modified in place. 413 This makes it easier to recognize *input* (read-only) and *output* arguments. 414 415 Do **not** use `const` when passing C types: `f()` and `g()` below are equivalent. 416 417 .. code-block:: c++ 418 419 double f(const double x) { 420 return x*x; 421 } 422 423 double g(double x) { 424 return x*x; 425 } 426 427 Method versus a function 428 ^^^^^^^^^^^^^^^^^^^^^^^^ 429 430 Do **not** implement something as a class method if the same functionality can be 431 implemented as a standalone function. Turn a class method into a standalone function if 432 you notice that it uses the *public* class interface only. 433 434 Virtual methods 435 ^^^^^^^^^^^^^^^ 436 437 - Do not make a method virtual unless you have to. 438 - Public methods should not be virtual (create "non-virtual interfaces") 439 - **Never** add `__attribute__((noreturn))` to a virtual class method. 440 441 private versus protected versus public 442 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 443 444 Most data members and class methods should be `private`. 445 446 Make it `protected` if it should be accessible from a derived class. 447 448 Make it `public` only if it is a part of the interface.