This is a set of guidelines for contributing to Chatterino. The goal is to teach programmers without C++ background (java/python/etc.), people who haven't used Qt or otherwise have different experience the idioms of the codebase. Thus we will focus on this which are different from those other environments. There are extra guidelines available here but they are considered as extras and not as important.
Code is automatically formatted using clang-format
. It take the burdon off of the programmer and ensures that all contributers use the same style (even if mess something up accidentally). We recommend that you set up automatic formatting on file save in your editor.
Arithmetic types (like char, short, int, long, float and double), bool, and pointers are NOT inititalized by default in c++. They keep whatever value is already at their position in the memory. This makes debugging harder and is unpredictable so we initialize them to zero by using {}
after their name when declaring them.
The way a parameter is passed signals how it is going to be used inside of the function. C++ doesn't have multiple return values so there is "out parameters" (reference to a variable that is going to assigned inside of the function) to simulate multiple return values.
Cheap to copy types like int/enum/etc. can be passed in per value since copying them is fast.
References mean that the variable doesn't need to be copied when it is passed to a function.
type | meaning |
---|---|
const Type& name |
in Parameter. It is NOT going to be modified and may be copied inside of the function. |
Type& name |
out or in+out Parmameter. It will be modified. |
Pointers signal that objects are managed manually. While the above are only guaranteed to live as long as the function call (= don't store and use later) these may have more complex lifetimes.
type | meaning |
---|---|
Type* name |
The lifetime of the parameter may exceed the length of the function call. It may use the QObject parent/children system. |
R-value references &&
work similar to regular references but signal the parameter should be "consumed".
Generally the lowest level of requirement should be used e.g. passing Channel&
instead of std::shared_ptr<Channel>&
(aka ChannelPtr
) if possible.
All functions names are in camelCase
. Private member variables are in camelCase_
(note the underscore at the end). We don't use the get
prefix for getters. We mark functions as const
if applicable.
(type)variable
.type(variable)
Always use this
to refer to instance members to make it clear where we use either locals or members.
Keep the element on the stack if possible. If you need a pointer or have complex ownership you should use one of these classes:
std::unique_ptr
if the resource has a single owner.std::shared_ptr
if the resource has multiple owners.variable->deleteLater()
instead of delete variable
. This ensures that it will be deleted on the correct thread.std::unique_ptr<Type, DeleteLater>
with DeleteLater
from "src/common/Common.hpp". This will call deleteLater()
on the pointer once it goes out of scope or the object is destroyed.Comments should only be used to:
Try to structure your code so that comments are not required.
Try to structure your code in a way that comments are not necessary.
The class checks if a string contains a link and and exposes members to check if a match was found, and the match .
The following function signature would make the intent even more obvious, but removed a layer of abstraction. It now exposes the fact that it uses QRegularExpression to find the link. Depeding on the use case this might be fine.