The recommended coding style for MeteoIO is the Kernel coding style with a few exceptions:
- We don't enforce strict 80 characters line width. Try to remain reasonable, but don't necessarily cut everything off at 80 characters
- Try to intelligently use spaces to visually group elements of a complex formula. If the formula can be split into meaningful elements, please do it (using some
const double element =constructs).
- Try to properly qualify variables: for example, if a variable will not be changed, will never be negative and always integer, then use
const unsigned intor even
static const doublefor a compilation-time constant. When some specific types are used for some standard library calls, use these types (for example,
- Use C++ method naming convention: a method name starts with lowercase letter and each individual word in a name starts capitalized. Usually, no underscores are used in a method. For example, a method that would return the lapse rate contained in an object would be named
- Qualify variables and parameters with
constwhen appropriate (see const-keyword)
- Do not declare all variables at the beginning of a function, as was fashionable 30 years ago! Declare variables in the most limited scope that makes sense: if a variable is only used as const in a loop, declare it in the loop (and most probably it can be declared as
const...). Of course, if the said variable is constant across all loop iterations, declare it as const outside the loop. If it is not const in the loop, then declare it outside the loop.
A few important points to emphasize (from the Kernel coding style):
- Functions should be short and sweet, and do just one thing. They should fit on one or two screens of text, and do one thing and do that well.
- If you have a complex function, and you suspect that a less-than-gifted first-year high-school student might not even understand what the function is all about, you should adhere to the maximum limits all the more closely. Use helper functions with descriptive names.
- Comments are good, but there is also a danger of over-commenting. Never try to explain how your code works in a comment: it's much better to write the code so that the working is obvious, and it's a waste of time to explain badly written code.
To summarize: consider that the next time you will have to debug your code will be on December 31st in the evening after you've enjoyed a glass of Champagne when a critical system just failed and must be brought back online at all costs in the next few hours (like an application for an avalanche warning service!).
Since every user has his/her own preference for the ideal indentation width, please use "smart tabs". That practically means:
- indent with tabs
- align with spaces
This way, each developer can set his/her indentation size as he/she wishes without forcing his/her choice to others...
Memory management and Containers
Please do NOT manage memory manually but use Standard Template Library (STL) containers instead. This dramatically reduces memory errors (ie: segfaults), often offers more performance and provides you with lots of associated algorithms (like sorting, search, filling, etc).
When you need your own data class, please design it based on these STL containers (like grid2DObject is based on std::vector).
Basically, this means that you will replace mallocs and arrays by vectors (for 1d, 2d, 3d grids), maps (for multiple key/value pairs), lists (for unordered table), etc
The recommended C++ usage should be followed: "throw by value, catch by reference" (as specified in C++ Coding Standards: 101 Rules, Guidelines, and Best Practices, Herb Sutter, Andrei Alexandrescu, 2004, Addison-Wesley Professional). Moreover, we should consider catching by const reference and not even declaring a variable if not doing anything with it: something like
catch( const IOException& ) would often be enough.
When compiling in debug mode, lots of warnings are enabled. This should be seen as valuable tips, not as an hindrance. But please fix every single warning before committing your code. Please also address the root cause of the warning, do not simply silent it: for example a warning about potentially uninitialized variable is not fixed by setting the variable to zero when declaring it, but by looking at how the variable might get used before being initialized to a proper value (it could be that the variable is only required in a more limited scope, that some cases have been forgotten, etc) and modifying the code and/or code structure in a way that fixes it.
Only in very rare cases a warning will be tolerated (or silenced), for example when using a
long long (which is supported by the newest version of c++ but we don't want to turn all older compilers off when they usually support
long long as a compiler extension).
Working with git
If a git local repository is on an NFS filesystem, it can get very slow. In this case, it is recommended to set
git config core.preloadindex true on the repository (as this is a per repository setting).
If you often rely on
git pull, you might have noticed that it gets you in trouble quite regularly... Based on a long explanation, you should change your worfklow:
git fetchin order to get the new commits (but not doing anything yet with these new commits);
git logto see what you got from the fetch;
git merge --ff-onlyin order to integrate all new commits when you did not make any changes on your side;
git rebaseto integrate all new commits and then re-commit your local changes as new commits on top of the new version;
git mergeif you really must do a real merge;
- configure git to only fast-forward by default when doing a pull with
git config --global pull.ff only.