So kmolcard hopped on board and asked if we have any coding standards. And we kinda dont beyond "it works" and "clang-format it" so maybe its finally time to write some things down, some of which we are kinda defacto doing and some of which we are not.
A few pre-comments
- This is a draft baconpaul wrote and is not yet something we agree on. Comments, ideas, concensus working. And maybe the best thing is to delete some sections and stay silent
- This document implies some changes but I explicitly think we should not do a massive retrofit of the code base. Use these guides for new stuff and for changes, but don't retrofit the whole code bsase
- This is a guide not a set of rules. Sometimes they won't work. Then skip them! Or skip them and add a comment. And some things are marked "prefer", so use judgement of course.
- Writing bad code which follows these standards is less good than writing good code which bends them with a comment!
So here goes
- namespaces are
sst::lower_case::names
- structs are
CamelCaseWithUpper
and arestruct
notclass
- struct members follow
mFooBar
for memberssThisThat
for static members
- constants are generally
static constexpr
either in a namespace or in a struct as appropriate- prefixed with a
k
for constants which are values.static constexpr float kDefaultCutoff{440.f};
- prefixed with an
n
ornum
for unsigned integral constants which are set sizes.static constexpr uint32_t numParts{8};
orstatic constexpr size_t nPatches{148}
or (somewhat controversially)static constexpr uint16_t nMaxVoices{256};
- enums
- enums are either commonly prefixed
ft_this, ft_that
or all upper case. - prefer class enums to non-class enums, especially in the prefixed form, using the class rules.
- enums can optionally have a
numBlah
final member if ordered.
- enums are either commonly prefixed
- template class arguments are
T
etc orUpperCase
- template int arguments follow the
int
constants member rules - local variables do whatever you want, but try to not conflict with the rules above. Like a local variable named
kCutoff
is pretty anti-social.
- We code to c++17 standard.
- Some of our builds still compile back to macos 10.9 so we have some light constraints on
<variant>
and<optional>
which CI will catch if you get them wrong. - use
std::filesystem
for all filesystem apis, through the various import aliases provided.
- Try to use explicit types from
<cstdint>
likeint16_t
oruint32_t
overint
. Unsigned matters! Give it some thought. - initialize class members inline with
{}
whenever possible. That is, prefer a declaration likeint mBlockCount{0};
in a class to: mBlockCount(0)
in the constructor initialization list. - whenever possible, use
auto
. But be careful ofauto f{0};
makes anint
not afloat
! - Prefer c-style
(int)std::round(f)
casts for fundamental types (int
,float
,uint8_t
etc...) but usestatic_cast<>
reinterpret_cast<>
ordynamic_cast<>
as appropriate in other cases. - Initalize literal constants with the correct type using prefixes.
1.2f
is a float;0U
is an unsigned 0. - prefer
const std::string &
toconst char *
- Prefer
std::unique_ptr
andstd::make_unique
to any other mechanism. - If you use
std::shared_ptr
write a comment explaining why. Sometimes you need it. - If you use
new
, you have probably made a mistake.
- If you can code to
const &
rather than*
, do so. Generally use references. - Having an object keep a
const &Foo mFoo
initialized in the constructor and set by usingStruct(*mUniqueThing)
is idiomatic.
- use
std::thread
for all apis - threads == bugs. If you are adding a thread, chat with some other devs to make sure.
- Use lambdas and
std::function
as a way to pass functions over prior c++ approaches if possible - Never use
[&]
- Be cautions if using
[=]
- All blocks have braces even one liners after an if.
- Dont allocate
- Use lock free data structures
- Stuck? Ask!
const
matters. Think about it and use it as much as you can.- Templates and specializations are better than virtual functions and inheritances especialy in the audio thread.
- The UI object model is the one place we use virtual a lot. That's fine.
- We end up using CRTP a lot. Dont know why but it works well