Serenity Operating System
at hosted 536 lines 12 kB view raw view rendered
1# Serenity C++ coding style 2 3For low-level styling (spaces, parentheses, brace placement, etc), all code should follow the format specified in `.clang-format` in the project root. 4 5**Important: Make sure you use `clang-format` version 8 or later!** 6 7This document describes the coding style used for C++ code in the Serenity Operating System project. All new code should conform to this style. 8 9We'll definitely be tweaking and amending this over time, so let's consider it a living document. :) 10 11 12### Names 13 14[](#names-basic) A combination of CamelCase and snake\_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. 15 16###### Right: 17 18```cpp 19struct Entry; 20size_t buffer_size; 21class FileDescriptor; 22String absolute_path(); 23``` 24 25###### Wrong: 26 27```cpp 28struct data; 29size_t bufferSize; 30class Filedescriptor; 31String MIME_Type(); 32``` 33 34[](#names-full-words) Use full words, except in the rare case where an abbreviation would be more canonical and easier to understand. 35 36###### Right: 37 38```cpp 39size_t character_size; 40size_t length; 41short tab_index; // More canonical. 42``` 43 44###### Wrong: 45 46```cpp 47size_t char_size; 48size_t len; 49short tabulation_index; // Goofy. 50``` 51 52[](#names-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\_". 53 54###### Right: 55 56```cpp 57class String { 58public: 59 ... 60 61private: 62 int m_length { 0 }; 63}; 64``` 65 66###### Wrong: 67 68```cpp 69class String { 70public: 71 ... 72 73 int length { 0 }; 74}; 75``` 76 77[](#names-setter-getter) 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. 78 79###### Right: 80 81```cpp 82void set_count(int); // Sets m_count. 83int count() const; // Returns m_count. 84``` 85 86###### Wrong: 87 88```cpp 89void set_count(int); // Sets m_the_count. 90int get_count() const; // Returns m_the_count. 91``` 92 93[](#names-out-argument) Precede getters that return values through out arguments with the word "get". 94 95###### Right: 96 97```cpp 98void get_filename_and_inode_id(String&, InodeIdentifier&) const; 99``` 100 101###### Wrong: 102 103```cpp 104void filename_and_inode_id(String&, InodeIdentifier&) const; 105``` 106 107[](#names-verb) Use descriptive verbs in function names. 108 109###### Right: 110 111```cpp 112bool convert_to_ascii(short*, size_t); 113``` 114 115###### Wrong: 116 117```cpp 118bool to_ascii(short*, size_t); 119``` 120 121[](#names-if-exists) When there are two getters for a variable, and one of them automatically makes sure the requested object is instantiated, prefix that getter function which with `ensure_`. As it ensures that an object is created, it should consequently also return a reference, not a pointer. 122 123###### Right: 124 125```cpp 126Inode* inode(); 127Inode& ensure_inode(); 128``` 129 130###### Wrong: 131 132```cpp 133Inode& inode(); 134Inode* ensure_inode(); 135``` 136 137[](#names-variable-name-in-function-decl) 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. 138 139###### Right: 140 141```cpp 142void set_count(int); 143 144void do_something(Context*); 145``` 146 147###### Wrong: 148 149```cpp 150void set_count(int count); 151 152void do_something(Context* context); 153``` 154 155[](#names-enum-to-bool) 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. 156 157###### Right: 158 159```cpp 160do_something(something, AllowFooBar::Yes); 161paint_text_with_shadows(context, ..., text_stroke_width > 0, is_horizontal()); 162set_resizable(false); 163``` 164 165###### Wrong: 166 167```cpp 168do_something(something, false); 169set_resizable(NotResizable); 170``` 171 172[](#names-enum-members) Enum members should use InterCaps with an initial capital letter. 173 174[](#names-const-to-define) Prefer `const` to `#define`. Prefer inline functions to macros. 175 176[](#names-define-constants) `#defined` constants should use all uppercase names with words separated by underscores. 177 178[](#header-guards) Use `#pragma once` instead of `#define` and `#ifdef` for header guards. 179 180###### Right: 181 182```cpp 183// MyClass.h 184#pragma once 185``` 186 187###### Wrong: 188 189```cpp 190// MyClass.h 191#ifndef MyClass_h 192#define MyClass_h 193``` 194 195### Other Punctuation 196 197[](#punctuation-member-init) 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. 198 199###### Right: 200 201```cpp 202class MyClass { 203 ... 204 Document* m_document { nullptr }; 205 int m_my_member { 0 }; 206}; 207 208MyClass::MyClass(Document* document) 209 : MySuperClass() 210 , m_document(document) 211{ 212} 213 214MyOtherClass::MyOtherClass() 215 : MySuperClass() 216{ 217} 218``` 219 220###### Wrong: 221 222```cpp 223MyClass::MyClass(Document* document) : MySuperClass() 224{ 225 m_myMember = 0; 226 m_document = document; 227} 228 229MyClass::MyClass(Document* document) : MySuperClass() 230 : m_my_member(0) // This should be in the header. 231{ 232 m_document = document; 233} 234 235MyOtherClass::MyOtherClass() : MySuperClass() {} 236``` 237 238[](#punctuation-vector-index) Prefer index or range-for over iterators in Vector iterations for terse, easier-to-read code. 239 240###### Right: 241 242```cpp 243for (auto& child : children) 244 child->do_child_thing(); 245``` 246 247 248#### OK: 249 250```cpp 251for (int i = 0; i < children.size(); ++i) 252 children[i]->do_child_thing(); 253``` 254 255###### Wrong: 256 257```cpp 258for (auto it = children.begin(); it != children.end(); ++it) 259 (*it)->do_child_thing(); 260``` 261 262### Pointers and References 263 264[](#pointers-cpp) **Pointer and reference types in C++ code** 265Both pointer types and reference types should be written with no space between the type name and the `*` or `&`. 266 267[](#pointers-out-argument) 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. 268 269###### Right: 270 271```cpp 272void MyClass::get_some_value(OutArgumentType& out_argument) const 273{ 274 out_argument = m_value; 275} 276 277void MyClass::do_something(OutArgumentType* out_argument) const 278{ 279 do_the_thing(); 280 if (out_argument) 281 *out_argument = m_value; 282} 283``` 284 285###### Wrong: 286 287```cpp 288void MyClass::get_some_value(OutArgumentType* outArgument) const 289{ 290 *out_argument = m_value; 291} 292``` 293 294### "using" Statements 295 296[](#using-ak) 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. 297 298###### Right: 299 300```cpp 301// AK/Vector.h 302 303namespace AK { 304 305} // namespace AK 306 307using AK::Vector; 308``` 309 310###### Wrong: 311 312```cpp 313// AK/Vector.h 314 315namespace AK { 316 317} // namespace AK 318 319using namespace AK; 320``` 321 322###### Wrong: 323 324```cpp 325// runtime/Object.h 326 327namespace AK { 328 329} // namespace AK 330 331using AK::SomethingOrOther; 332``` 333 334[](#using-in-cpp) In C++ implementation files, do not use "using" declarations of any kind to import names in the standard template library. Directly qualify the names at the point they're used instead. 335 336###### Right: 337 338```cpp 339// File.cpp 340 341std::swap(a, b); 342c = std::numeric_limits<int>::max() 343``` 344 345###### Wrong: 346 347```cpp 348// File.cpp 349 350using std::swap; 351swap(a, b); 352``` 353 354###### Wrong: 355 356```cpp 357// File.cpp 358 359using namespace std; 360swap(a, b); 361``` 362 363### Types 364 365[](#types-unsigned) Omit "int" when using "unsigned" modifier. Do not use "signed" modifier. Use "int" by itself instead. 366 367###### Right: 368 369```cpp 370unsigned a; 371int b; 372``` 373 374###### Wrong: 375 376```cpp 377unsigned int a; // Doesn't omit "int". 378signed b; // Uses "signed" instead of "int". 379signed int c; // Doesn't omit "signed". 380``` 381 382### Classes 383 384[](#classes-explicit) 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. 385 386###### Right: 387 388```cpp 389class LargeInt { 390public: 391 LargeInt(int); 392... 393 394class Vector { 395public: 396 explicit Vector(int size); // Not a type conversion. 397 Vector create(Array); // Costly conversion. 398... 399 400``` 401 402###### Wrong: 403 404```cpp 405class Task { 406public: 407 Task(ExecutionContext&); // Not a type conversion. 408 explicit Task(); // No arguments. 409 explicit Task(ExecutionContext&, Other); // More than one argument. 410... 411``` 412 413### Singleton pattern 414 415[](#singleton-static-member) Use a static member function named "the()" to access the instance of the singleton. 416 417###### Right: 418 419```cpp 420class UniqueObject { 421public: 422 static UniqueObject& the(); 423... 424``` 425 426###### Wrong: 427 428```cpp 429class UniqueObject { 430public: 431 static UniqueObject& shared(); 432... 433``` 434 435###### Wrong: 436 437```cpp 438class UniqueObject { 439... 440}; 441 442UniqueObject& my_unique_object(); // Free function. 443``` 444 445### Comments 446 447[](#comments-sentences) Make comments look like sentences by starting with a capital letter and ending with a period (punctation). One exception may be end of line comments like this `if (x == y) // false for NaN`. 448 449[](#comments-fixme) Use FIXME: (without attribution) to denote items that need to be addressed in the future. 450 451###### Right: 452 453```cpp 454draw_jpg(); // FIXME: Make this code handle jpg in addition to the png support. 455``` 456 457###### Wrong: 458 459```cpp 460draw_jpg(); // FIXME(joe): Make this code handle jpg in addition to the png support. 461``` 462 463```cpp 464draw_jpg(); // TODO: Make this code handle jpg in addition to the png support. 465``` 466 467### Overriding Virtual Methods 468 469[](#override-methods) The declaration of a virtual method inside a class must be declared with the `virtual` keyword. All subclasses of that class must either specify 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. 470 471###### Right: 472 473```cpp 474class Person { 475public: 476 virtual String description() { ... }; 477} 478 479class Student : public Person { 480public: 481 virtual String description() override { ... }; // This is correct because it only contains the "override" keyword to indicate that the method is overridden. 482} 483 484``` 485 486```cpp 487class Person { 488public: 489 virtual String description() { ... }; 490} 491 492class Student : public Person { 493public: 494 virtual String description() final { ... }; // This is correct because it only contains the "final" keyword to indicate that the method is overridden and that no subclasses of "Student" can override "description". 495} 496 497``` 498 499###### Wrong: 500 501```cpp 502class Person { 503public: 504 virtual String description() { ... }; 505} 506 507class Student : public Person { 508public: 509 String description() override { ... }; // This is incorrect because it uses only the "override" keywords to indicate that the method is virtual. Instead, it should use both the "virtual" and "override" keywords. 510} 511``` 512 513```cpp 514class Person { 515public: 516 virtual String description() { ... }; 517} 518 519class Student : public Person { 520public: 521 String description() final { ... }; // This is incorrect because it uses only the "final" keywords to indicate that the method is virtual and final. Instead, it should use both the "virtual" and "final" keywords. 522} 523``` 524 525```cpp 526class Person { 527public: 528 virtual String description() { ... }; 529} 530 531class Student : public Person { 532public: 533 virtual String description() { ... }; // This is incorrect because it uses the "virtual" keyword to indicate that the method is overridden. 534} 535``` 536