.clang-format in the project root.
This document describes the coding style used for C++ code in the Ladybird Browser project. All new code should conform to this style.
We’ll definitely be tweaking and amending this over time, so let’s consider it a living document. :)
Names
A combination of CamelCase, snake_case, and SCREAMING_CASE:- Use CamelCase (Capitalize the first letter, including all letters in an acronym) in a class, struct, or namespace name
- Use snake_case (all lowercase, with underscores separating words) for variable and function names
- Use SCREAMING_CASE for constants (both global and static member variables)
Right
Wrong
Matching spec naming
When implementing spec algorithms and other constructs that a spec explicitly names, prefer closely matching the same names the spec uses, whenever possible. Given the construct at https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-being-missing which has the literal name “Suffering from being missing” in the spec, for example:Full words vs abbreviations
Use full words, except in the rare case where an abbreviation would be more canonical and easier to understand.Data members
Data members in C++ classes should be private. Static data members should be prefixed by “s_”. Other data members should be prefixed by “m_”. Global variables should be prefixed by “g_”.Setters and getters
Precede setters with the word “set”. Use bare words for getters. Setter and getter names should match the names of the variables being set/gotten.Function names
Use descriptive verbs in function names.The ensure_ prefix
When there are two getters for a variable, and one of them automatically makes sure the requested object is instantiated, prefix that getter function withensure_. As it ensures that an object is created, it should consequently also return a reference, not a pointer.
Function parameters
Leave meaningless variable names out of function declarations. A good rule of thumb is if the parameter type name contains the parameter name (without trailing numbers or pluralization), then the parameter name isn’t needed. Usually, there should be a parameter name for bools, strings, and numerical types.Enums vs bools
Prefer enums to bools on function parameters if callers are likely to be passing constants, since named constants are easier to read at the call site. An exception to this rule is a setter function, where the name of the function already makes clear what the boolean is.Enum members
Enum members should use InterCaps with an initial capital letter.Header guards
Use#pragma once instead of #define and #ifdef for header guards.
Other punctuation
Constructor initialization
Constructors for C++ classes should initialize their members using C++ initializer syntax. Each member (and superclass) should be indented on a separate line, with the colon or comma preceding the member on that line. Prefer initialization at member definition whenever possible.Vector iterations
Prefer index or range-for over iterators in Vector iterations for terse, easier-to-read code.Pointers and references
Both pointer types and reference types should be written with no space between the type name and the* or &.
An out argument of a function should be passed by reference except rare cases where it is optional in which case it should be passed by pointer.
”using” statements
In header files in the AK sub-library, however, it is acceptable to use “using” declarations at the end of the file to import one or more names in the AK namespace into the global scope.Types
Omit “int” when using “unsigned” modifier. Do not use “signed” modifier. Use “int” by itself instead.Classes
For types with methods, preferclass over struct.
- For classes, make public getters and setters, keep members private with
m_prefix. - For structs, let everything be public and skip the
m_prefix.
Implicit conversions
Use a constructor to do an implicit conversion when the argument is reasonably thought of as a type conversion and the type conversion is fast. Otherwise, use the explicit keyword or a function returning the type. This only applies to single argument constructors.Singleton pattern
Use a static member function named “the()” to access the instance of the singleton.Comments
Comments should be written using// and not /* */, except for the copyright notice.
Write comments as proper sentences starting with a capital letter and ending with a period (or other punctuation). One exception may be end of line comments like this: if (x == y) // false for NaN
Another exception is comments copied from specifications. These should be quoted verbatim, and not modified except for wrapping or to insert necessary punctuation such as adding ** when a number is raised to a power, as this is often done using elements like <sup> which do not appear in the copied text.
Please wrap long comments onto multiple lines so that they are easier to read. Generally, 120 characters is a good width to aim for.
Use FIXME: (without attribution) to denote items that need to be addressed in the future. TODO: (without attribution) is also permitted.
Spec notes
Many web specs include notes that are prefixed withNOTE: .... To allow for verbatim copying of these notes into our code, we retain the NOTE: prefix and use NB: for our own notes.
This only applies to comments as part of code that is directly implementing a spec algorithm or behavior. Comments in other places do not need a prefix.
Overriding virtual methods
The declaration of a virtual method inside a class must be declared with thevirtual keyword. All subclasses of that class must also specify either the override keyword when overriding the virtual method, or the final keyword when overriding the virtual method and requiring that no further subclasses can override it.
Const placement
Use “east const” style whereconst is written on the right side of the type being qualified. See this article for more information about east const.
Casts
Before you consider a cast, please see if your problem can be solved another way that avoids the visual clutter.- Integer constants can be specified to have (some) specific sizes with postfixes like
u, l, uletc. The same goes for single-precision floating-point constants withf. - Working with smaller-size integers in arithmetic expressions is hard because of implicit promotion. Generally, it is fine to use
intand other “large” types in local variables, and possibly cast at the end. - If you
const_cast, really consider whether your APIs need to be adjusted in terms of their constness. Does the member function you’re writing actually make sense to beconst? - If you do checked casts between base and derived types, also consider your APIs. For example: Does the function being called actually need to receive the more general type or is it fine with the more specialized type?
static_cast, reinterpret_cast, bit_cast, dynamic_cast etc.
There is a single exception to this rule: marking a function parameter as used with (void)parameter;.
Omission of curly braces from statement blocks
Curly braces may only be omitted fromif/else/for/while/etc. statement blocks if the body is a single line.
Additionally, if any body of a connected if/else statement requires curly braces according to this rule, all of them do.