Contributing to Regina
This page serves as a checklist for adding new code to Regina.
Regina is written in C++, and so any permanent contributions to Regina will need to be written in C++ also.
New classes should use value semantics, unless there is a good reason not to. Classes with value semantics should provide appropriate comparisions (
!=), copy constructors, and copy assignment operators. If they are large objects, they should also provide move constructors, move assignment operators, a member
swap()function, and a global
New code should ideally come with corresponding tests for Regina's test suite:
- For important classes, these tests should be comprehensive,
not just a few token cases. See the
testsuite/maths/integer.cppfor an example of very comprehensive testing.
- The tests may be either C++ (in
testsuite/) or Python (in
python/testsuite/), or both. Python tests are simpler to write; however, the C++ tests can be far more flexible in what is tested (not just comparing text output), and moreover the C++ tests will be run on more systems (including those where Python development files are not available).
- Whilst they should be comprehensive, tests should not
be enormously slow. Watch how fast/slow the other tests are as a guide
for what is acceptable (if you test using
make test ARGS=-V” then you can see each individual test as it runs).
- For important classes, these tests should be comprehensive, not just a few token cases. See the
All functions and classes should be fully documented. In particular, for each function:
- The first sentence of the documentation should be appropriate to display as a brief synopsis (since this will be extracted and placed into various indices).
- The documentation should list all preconditions that the user needs to ensure before calling the function.
- Functions should not be correct only for “common” scenarios, but should be as general as possible within reason. Any limitations should be made clear to the user (e.g., through explicit preconditions)—users should not be expected to guess which scenarios the function works for.
- All parameters should be described in individual
\paramblocks. Likewise, any non-type template parameters (e.g., integer template parameters) must be described in
\tparamblocks. Of course, type parameters may be described also if this will be helpful. The return value should be described in a
- All preconditions that the user is expected to adhere to
should be spelled out in the documentation. Limits on function
arguments (e.g., acceptable integer ranges) can be listed in each
\paramblock; other preconditions should be listed in separate
- If there are differences between the C++ and Python
versions of a function or class, these should be listed in a separate
\pythonparagraph. In particular, if function arguments differ (e.g., the C++ version takes a pair of iterators but the Python version takes a single list), then the arguments should be named in the Python bindings using
pybind11::arg(...). If there is no Python version at all, this should be made clear using a
\nopythontag (which can take an optional explanation).
Documentation needs to be written in a format that is easy for humans to read in the C++ headers, will be formatted appropriately when processed by Doxygen, and will convert sensibly to a Python docstring. Best practices include:
- Avoid HTML tags such as
<tt>where possible—instead use markdown and/or Doxygen tags. In particular: for italicised English, use
_underscores_; for italicised variable names use
\a; for bold English use
**double asterisks**; for C++ keywords use
\c; and for inline code fragments use
`backticks`. Note that Doxygen does not (currently) translate underscores within
\exceptionblocks; here you will need to italicise using
\e(for single words) or
<i>(for multiple words).
- Avoid XML entities such as
≠. For less-than, you can use
\<if there is a risk of Doxygen misinterpreting a plain
<as an HTML tag. For mathematical symbols with “simple” unicode representations (i.e., likely to be supported in fonts across many platforms), just use the unicode instead. Simple unicode symbols include:
- Use Doxygen-style backslash tags such as
\param, not Javadoc-style tags such as
- Avoid HTML tags such as
All C++ functions and classes should have corresponding Python bindings, unless there is a very good reason not to. The Python bindings are typically easy to write, and Ben can help with this if necessary.
- Template classes should be wrapped in Python using
suffixes that describe the template arguments.
See for example
- All functions and classes wrapped in Python should have
appropriate docstrings, which need to be passed to the corresponding
pybind11::def(...)statement. These docstrings are extracted automatically from the hand-written documentation in the C++ headers, and this extraction is done manually (not as part of the build process). Please ask Ben if you need this extraction to be run for you.
- If for some reason you are binding a function in Python
but you do not want to extract a docstring (this should be a rare
occurrence), use a
\nodocstringtag in the C++ class or function documentation. (At the time of writing,
\nodocstringis used in only two places across Regina's entire API.)
- Template classes should be wrapped in Python using suffixes that describe the template arguments. See for example
|API Documentation||Up||Troubleshooting and FAQ|