D++ (DPP)
C++ Discord API Bot Library
|
This page lists the coding style we stick to when maintaining the D++ library. If you are submitting a pull request or other code contribution to the library, you should stick to the styles listed below. If something is not covered here, ask on the official discord server!
All class, variable/member, function and method names should use snake_case
, similar to the style of the C++ standard library.
Enums and their values should be snake_case
as with class, function and method names. You do not need to use enum class
, so make sure that enum values are prefixed with a prefix to make them unique and grouped within the IDE, e.g. ll_debug
, ll_trace
etc.
Open curly braces on the same line as the keyword, for example:
Use a space after the comma in parameter lists, and after closing brackets and before opening brackes except when calling a function, e.g.:
Indentation should always be tab characters. It is up to you how wide you set tab characters in your editor for your personal tastes. All code blocks delimited within curly braces should be indented neatly and uniformly.
Constants and macros should be all UPPERCASE
with SNAKE_CASE
to separate words. Macros should not have any unexpected side effects.
All comments should be in doxygen
format (similar to javadoc). Please see existing class definitions for an example. You should use doxygen style comments in a class definition inside a header file, and can use any other comment types within the .cpp file. Be liberal with comments, especially if your code makes any assumptions!
If you export a class which is to be accessible to users, be sure to prefix it with the CoreExport
macro, for example:
The CoreExport
macro ensures that on certain platforms (notably Windows) the symbol is exported to be available to the library user.
It is a design philosophy of D++ that everything possible in a class should be public, unless the user really does not need it (you should consider justifying in comments why) or user adjustment of the variable could badly break the functioning of the library. Avoid the use of accessors for setting/getting values in a class, except for bit fields, where you should provide accessors for setting and getting individual bits (for example, see user.h
), or in the event you want to provide a "fluent" interface.
Keep levels of inheritence low. If you need to inherit more than 3 levels deep, it is probable that the design could be simplified. Remember that at scale, there can be tens of millions of certain classes and each level of virtual nesting adds to the vtable
of that object's instance in RAM.
Where discord provides boolean flags, if the user is expected to store many of the object in RAM, or in cache, you should pack all these booleans into bit fields (see user.h
and channel.h
for examples). In the event that the object is transient, such as an interaction or a message, packing the data into bit fields is counter intuitive. Remember that you should provide specific accessors for bit field values!
Where you are making use of an external dependency such as opus
or libssl
, do not place references to the types/structs, or the header files of these external libraries within the header files of D++. Doing so adds that library as a public dependency to the project (which is bad!). Instead make an opaque class, and/or forward-declare the structs (for examples see sslclient.h
and discordvoiceclient.h
).
Where discord provide a name in PascalCase we should stick as closely to that name as possible but convert it to snake_case
. For example, GuildMember would become guild_member
.
Do not introduce platform specific (e.g. windows only) code or libc functions. If you really must use these functions safely wrap them e.g. in #ifdef _WIN32
and provide a cross-platform alternative so that it works for everyone.
If a value will only hold values up to 255, use uint8_t
. If a value cannot hold over 65536, use uint16_t
. These types can help use a lot less ram at scale.
Where possible, if you are adding methods to a class you should consider fluent design. Fluent design is the use of class methods tha return a reference to self (via return *this
), so that you can chain object method calls together (in the way dpp::message
and dpp::embed
do). For example:
This would allow the user to do this:
All types for the library should be within the dpp
namespace. There are a couple of additional namespaces, e.g. dpp::utility
for static standalone helper functions and helper classes, and dpp::events
for internal websocket event handlers.
All pull requests ("PRs") should be submitted against the dev
branch in GitHub. It’s good to have descriptive commit messages, or PR titles so that other contributors can understand about your commit or the PR Created. Read conventional commits for information on how we like to format commit messages.
All PRs must pass the GitHub Actions tests before being allowed to be merged. This is to ensure that no code committed into the project fails to compile on any of our officially supported platforms or architectures.