This document describes some common coding conventions and policy decisions used when creating Nano.
If you find some code within Nano that does not appear to follow these rules, please let me know!
The NanoTest application contains a set of unit tests for validating Nano.
Ideally each class should have complete coverage of its public methods, and a new test is added whenever a bug is found.
Nano relies heavily on assertions to detect errors, and every function will ideally assert something about each of its parameters or any preconditions.
Assertions are also used within functions to identify problems as they occur, and may be used to validate the result prior to returning any error.
Nano must always compile without warnings, and compiler warnings are treated as bugs.
Nano is built with -Wall and -Wextra, as well as several additional flags to catch warnings not covered by these flags.
Nano follows the "Get/Create" naming convention used by CoreFoundation.
GetXXX methods either return by value, or return a const pointer/reference to data that the caller may access (subject to the owner's lifetime) but does not own.
CreateXXX methods will create a new instance of an object, or allocate new data. In either case, the caller takes ownership of the result and must dispose of it when necessary.
SetXXX methods typically take parameters by value or perform a deep copy of any pointer/reference parameters, allowing the caller to assume the parameter was retained or copied.
However, Nano typically uses a RAII pattern with copy-on-write rather than returning pointers. This allows objects to be copied with very low overhead and treated as simple scalars.
Whenever possible, Nano objects perform a deep copy when assigning values.
This approach helps simplify memory ownership, since objects can be passed around via assignment as if they were a simple type such as an int or a float.
NSharedValue provides copy-on-write behaviour for objects that manipulate potentially large amounts of data, allowing them to obtain deep copy behaviour without actually performing a copy.
Errors within Nano are typically returned to the caller to handle.
Errors returned by system APIs are either used to return failure, or asserted on with NN_ASSERT_NOERR if the caller would typically discard them.
Even if an error is returned to the caller, methods will frequently assert on kNoErr if an error would be unusual. Although the error would still need to be handled, this approach helps identify problems at the point of failure.
The Nano library does not use exceptions, and will always return errors to the caller rather than throwing an exception.