1422fb5e3936c9d3de95af3edd7caeaa2b91ede3
[alexxy/gromacs.git] / docs / dev-manual / language-features.rst
1 Allowed language features
2 =========================
3
4 Most of these are not strict rules, but you should have a very good
5 reason for deviating from them.
6
7 Portability considerations
8 ^^^^^^^^^^^^^^^^^^^^^^^^^^
9
10 Most |Gromacs| files compile as C++14, but some files remain that compile as C99.
11 C++ has a lot of features, but to keep the source code maintainable and easy to read, 
12 we will avoid using some of them in |Gromacs| code. The basic principle is to keep things 
13 as simple as possible.
14
15 * MSVC supports only a subset of C99 and work-arounds are required in those cases.
16 * We should be able to use virtually all C++14 features outside of OpenCL kernels
17   (which compile as C), and for consistency also in CUDA kernels.
18
19 C++ Standard Library
20 --------------------
21
22 |Gromacs| code must support the lowest common denominator of C++14 standard library
23 features available on supported platforms.
24 Some modern features are useful enough to warrant back-porting.
25 Consistent and forward-compatible headers are provided in ``src/gromacs/compat/``
26 as described in the `Library documentation <../doxygen/html-lib/group__group__compatibility.xhtml>`_
27
28 General considerations
29 ^^^^^^^^^^^^^^^^^^^^^^
30 As a baseline, |Gromacs| follows the C++ Core Guidelines |linkref1|, unless
31 our own more specific guidelines below say otherwise. We tend to be more restrictive
32 in some areas, both because we depend on the code compiling with a lot of different
33 C++ compilers, and because we want to increase readability. However, |Gromacs| is an
34 advanced projects in constant development, and as our needs evolve we will both
35 relax and tighten many of these points. Some of these changes happen naturally as
36 part of agreements in code review, while major parts where we don't agree should be
37 pushed to a redmine thread. Large changes should be suggested early in the development
38 cycle for each release so we avoid being hit by last-minute compiler bugs just before
39 a release.
40
41 * Use namespaces. Everything in ``libgromacs`` should be in a ``gmx``
42   namespace. Don't use using in headers except possibly for aliasing
43   some commonly-used names, and avoid file-level blanket ``using
44   namespace gmx`` and similar. If only a small number of ``gmx``
45   namespace symbols needed in a not-yet-updated file, consider
46   importing just those symbols. See also |linkref2|.
47 * Use STL, but do not use iostreams outside of the unit tests. iostreams can have
48   a negative impact on performance compared to other forms 
49   of string streams, depending on the use case. Also, they don't always
50   play well with using C ``stdio`` routines at the same time, which
51   are used extensively in the current code. However, since Google tests
52   rely on iostreams, you should use it in the unit test code.
53 * Don't use non-const references as function parameters. They make it
54   impossible to tell whether a variable passed as a parameter may
55   change as a result of a function call without looking up the
56   prototype.
57 * Use ``not_null<T>`` pointers wherever possible to convey the
58   semantics that a pointer to a valid is required, and a reference
59   is inappropriate. See also |linkrefnotnull1| and |linkrefnotnull2|.
60 * Use ``string_view`` in cases where you want to only use a read-only-sequence
61   of characters instead of using ``const std::string &``. See also |linkrefstringview|.
62   Because null termination expected by some C APIs (e.g. fopen, fputs, fprintf)
63   is not guaranteed, string_view should not be used in such cases.
64 * Use ``optional<T>`` types in situations where there is exactly one,
65   reason (that is clear to all parties) for having no value of type T,
66   and where the lack of value is as natural as having any regular
67   value of T, see |linkoptionalboost|. Good examples include the return type of a
68   function that parses an integer value from a string, searching for a matching
69   element in a range, or providing an optional name for a residue
70   type. Do use optional for lazy loading of resources, e.g., objects that have
71   no default constructor and are hard to construct.
72   Prefer other constructs when the logic requires an explanation of the
73   reason why no regular value for T exists, e.g.,  do not use ``optional<T>``
74   for error handling. 
75   ``optional<T>`` "models an object, not a pointer, even though operator*() and
76   operator->() are defined" (|linkoptionalcppref|). No dynamic memory allocation
77   ever takes place and forward declaration of objects stored in ``optional<T>``
78   does not work. Thus refrain from optional when passing handles; in contrast to
79   unique_ptr, optional has value semantics, not reference semantics.
80 * Don't use C-style casts; use ``const_cast``, ``static_cast`` or
81   ``reinterpret_cast as appropriate``. See the point on RTTI for
82   ``dynamic_cast``. For emphasizing type (e.g. intentional integer division)
83   use constructor syntax. For creating real constants use the user-defined literal
84   _real (e.g. 2.5_real instead of static_cast<real>(2.5)).
85 * Use signed integers for arithmetic (including loop indices). Use ssize
86   (available as free function and member of ArrayRef) to avoid casting.
87 * Avoid overloading functions unless all variants really do the same
88   thing, just with different types. Instead, consider making the
89   function names more descriptive.
90 * Avoid using default function arguments. They can lead to the code
91   being less readable than without (see |linkref3|). If you think that your specific
92   case improves readability (see |linkref4|), you can justify their use.
93 * Don't overload operators before thorough consideration whether it
94   really is the best thing to do. Never overload ``&&``, ``||``, or
95   the comma operator, because it's impossible to keep their original
96   behavior with respect to evaluation order.
97 * Try to avoid complex templates, complex template specialization or
98   techniques like SFINAE as much as possible. If nothing else, they
99   can make the code more difficult to understand.
100 * Don't use multiple inheritance. Inheriting from multiple pure
101   interfaces is OK, as long as at most one base class (which should be
102   the first base class) has any code. Please also refer to the
103   explanation |linkref5| and |linkref6|.
104 * Don't write excessively deep inheritance graphs. Try to not inherit
105   implementation just to save a bit of coding; follow the principle
106   "inherit to be reused, not to reuse." Also, you should not
107   mix implementation and interface inheritance. For explanation please
108   see |linkref7|.
109 * Don't include unnecessary headers. In header files, prefer to
110   forward declare the names of types used only "in name" in the header
111   file. This reduces compilation coupling and thus time. If a source
112   file also only uses the type by name (e.g. passing a pointer received
113   from the caller to a callee), then no include statements are needed!
114 * Make liberal use of assertions to help document your intentions (but
115   prefer to write the code such that no assertion is necessary).
116 * Prefer ``GMX_ASSERT()`` and ``GMX_RELEASE_ASSERT()`` to naked
117   ``assert()`` because the former permit you to add descriptive text.
118 * Use gmx::Mutex rather than pthreads, std or raw thread-MPI mutexes.
119 * Use proper enums for variable whose type can only contain one of a
120   limited set of values. C++ is much better than C in catching errors
121   in such code. Ideally, all enums should be typed enums, please
122   see |linkref8|. 
123 * When writing a new class, think whether it will be necessary to make
124   copies of that class. If not, declare the copy constructor and the
125   assignment operator as private and don't define them, making any
126   attempt to copy objects of that class fail. If you allow copies,
127   either provide the copy constructor and the assignment operator, or
128   write a clear comment that the compiler-generated ones will do (and
129   make sure that they do what you
130   want). ``src/gromacs/utility/classhelpers.h`` has some convenience
131   macros for doing this well.
132   You can also use deleted functions in this case.
133 * Declare all constructors with one parameter as explicit unless you
134   really know what you are doing. Otherwise, they can be used for
135   implicit type conversions, which can make the code difficult to
136   understand, or even hide bugs that would be otherwise reported by
137   the compiler. For the same reason, don't declare operators for
138   converting your classes to other types without thorough
139   consideration. For an explanation, please see |linkref9|.
140 * Write const-correct code (no ``const_cast`` unless absolutely
141   necessary).
142 * Avoid using RTTI (run-time type information, in practice
143   ``dynamic_cast`` and ``typeid``) unless you really need it. The cost
144   of RTTI is very high, both in binary size (which you always
145   pay if you compile with it) and in execution time (which you pay
146   only if you use it). If your problem seems to require RTTI, think
147   about whether there would be an alternative design that
148   wouldn't. Such alternative designs are often better.
149 * Don't depend on compiler metadata propagation. struct elements
150   and captured lambda parameters tend to have ``restrict`` and
151   alignment qualifiers discarded by compilers, so when you later
152   define an instance of that structure or allocate memory to
153   hold it, the data member might not be aligned at all.
154 * Plan for code that runs in compute-sensitive kernels to have useful
155   data layout for re-use, alignment for SIMD memory operations
156 * Recognize that some parts of the code have different requirements -
157   compute kernels, mdrun setup code, high-level MD-loop code,
158   simulation setup tools, and analysis tools have different needs, and
159   the trade-off point between correctness vs reviewer time vs
160   developer time vs compile time vs run time will differ.
161
162
163 .. |linkref1| replace:: `c++ guidelines <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines>`__
164 .. |linkref2| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#sf7-dont-write-using-namespace-in-a-header-file>`__
165 .. |linkref3| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i23-keep-the-number-of-function-arguments-low>`__
166 .. |linkref4| replace:: `here <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f51-where-there-is-a-choice-prefer-default-arguments-over-overloading>`__
167 .. |linkref5| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c135-use-multiple-inheritance-to-represent-multiple-distinct-interfaces>`__
168 .. |linkref6| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c136-use-multiple-inheritance-to-represent-the-union-of-implementation-attributes>`__
169 .. |linkref7| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c129-when-designing-a-class-hierarchy-distinguish-between-implementation-inheritance-and-interface-inheritance>`__
170 .. |linkref8| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Renum-class>`__
171 .. |linkref9| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-explicit>`__
172 .. |linkrefnotnull1| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-nullptr>`__
173 .. |linkrefnotnull2| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-nullptr>`__
174 .. |linkrefstringview| replace:: `here <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines.html#Rstr-view>`__
175 .. |linkoptionalboost| replace:: `here <https://www.boost.org/doc/libs/release/libs/optional>`__
176 .. |linkoptionalbartek| replace:: `here <https://www.bfilipek.com/2018/05/using-optional.html>`__
177 .. |linkoptionalcppref| replace:: `cppreference <https://en.cppreference.com/w/cpp/utility/optional>`__
178
179 .. _implementing exceptions:
180
181 Implementing exceptions for error handling
182 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
183 See :ref:`error handling` for the approach to handling run-time
184 errors, ie. use exceptions.
185
186 * Write exception-safe code. All new code has to offer at least the
187   basic or nothrow guarantee to make this feasible.
188 * Use std (or custom) containers wherever possible.
189 * Use smart pointers for memory management. By default, use
190   ``std::unique_ptr`` and ``gmx::unique_cptr`` in assocation with any
191   necessary raw ``new`` or ``snew`` calls. ``std::shared_ptr`` can be
192   used wherever responsibility for lifetime must be shared.
193   Never use ``malloc``.
194 * Use RAII for managing resources (memory, mutexes, file handles, ...).
195 * It is preferable to avoid calling a function which might throw an
196   exception from a legacy function which is not exception safe. However,
197   we make the practical exception to permit the use of features such
198   as ``std::vector`` and ``std::string`` that could throw
199   ``std::bad_alloc`` when out of memory. In particular, |Gromacs| has
200   a lot of old C-style memory handling that checking tools continue
201   to issue valid warnings about as the tools acquire more
202   functionality, and fixing these with old constructs is an
203   inefficient use of developer time.
204 * Functions / methods should be commented whether they are exception
205   safe, whether they might throw an exception (even indirectly), and
206   if so, which exception(s) they might throw.
207
208 Preprocessor considerations
209 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
210 * Don't use preprocessor defines for things other than directly
211   related to configuring the build. Use templates or inline functions
212   to generate code, and enums or const variables for constants.
213 * Preprocessing variables used for configuring the build should be
214   organized so that a valid value is always defined, i.e. we never
215   test whether one of our preprocessor variables is defined, rather we
216   test what value it has. This is much more robust under maintance,
217   because a compiler can tell you that the variable is undefined.
218 * Avoid code with lengthy segments whose compilation depends on #if
219   (or worse, #ifdef of symbols provided from outside |Gromacs|).
220 * Prefer to organize the definition of a const variable at the top of
221   the source code file, and use that in the code.  This helps keep all
222   compilation paths built in all configurations, which reduces the
223   incidence of silent bugs.
224 * Indent nested preprocessor conditions if nesting is necessary and
225   the result looks clearer than without indenting.
226 * Please strongly consider a comment repeating the preprocessor condition at the end
227   of the region, if a lengthy region is neccessary and benefits from
228   that. For long regions this greatly helps in understanding 
229   and debugging the code.