Kariba
|
In particular, containers such as std::vector, std::array, std::string, std::tuple, etc can be very useful, safe, and often faster.
Further, use C++ features: e.g., if you are using a struct to group variables, the struct can be declared and initialized C++ style, not so much C style:
(the first line prints 1 -1
, the second 5 -1
.)
If your functions start becoming 100 lines or more, or even exceed 50 lines, consider splitting it up in various subfunctions.
This has multiple advantages
Do write documentation strings. It always helps both your future slef and others to figure out what is going on in the respective function, or what variables are intended for (but clear variable names also help). Don't write what the code actually does (the infamous i++; // increase i by 1
example), but write what the intent is, the underlying algorithm and possibly (a) reference(s).
The style for docstrings is Doxygen's Qt style, with docstrings starting with /*!
or //!
. See https://www.doxygen.nl/manual/docblocks.html for some details, but generally, follow the overall style in the code.
This is a general style guide for writing code in the Kariba library. It can, of course, also be used outside of the library, but this is not necessary.
The code is formatted with clang-format
; this tool can often be installed using a package manager. There is a .clang-format
file with some definitions for the style (there are many more options). This ensures a consistent look and feel across the code.
In particular, it will:
a=1+1
becomes a = 1 + 1
).for(i=0
-> for (i = 0
)(double)a
-> (double) a`)a = 1; // comment
-> a = 1; // comment
)The various whitespace additions are to make the code (and comments) hopefully more readable.
Class names follow PascalCase: each (sub)word is started with a capital. This is done in a rather relaxed manner: BBody
instead of BlackBody
, Powerlaw
and Cyclosyn
instead of PowerLaw
and CycloSyn
.
Function and variable names are snake_case: use underscores to separate parts of the function. The underscore tends to read better (more space) than with camelCase, where long names can become cumbersome to read (a_very_long_variable_name
vs aVeryLongVariableName
).
Include header files only where they are needed: sometimes, they are needed only in the cpp file, so don't include them in the related hpp file. If both files need them, include them in both.
Be aware that the order of header files shouldn't matter. In fact, clang-format will order the header files alphabetically.
An example of the latter where the order of include files causes a problem:
a.h
includes <vector>
b.h
defines a function func
using std::vector
(as return type of one of its arguments), but does not include <vector>
.c.cpp
includes a.h
before b.h
(and doesn't include vector
itself). Therefore, when the preprocessor has finished, the <vector>
is included before func
is defined, and the compilation works fine.c.cpp
includes b.h
before a.h
, after the preprocessing stage, func
is defined before vector
is included, and the compilation will fail.Try and include some basic unit tests with your new functionality. Take care of covering edge cases, such as NaN or infinity in the input, out-of-range values as input, empty inputs (0-size vectors) and other edge cases. A few basic tests can cover the normal cases.
See the EBL unit tests as an example of covering edge cases, and running a few tests for more normal cases.