Difference between revisions of "Code style guidelines"

From Minetest Developer Wiki
Jump to navigation Jump to search
m ((summary && (*summary = "<oneline>") || error("missing summary"));)
(Improve formatting and writing style)
Line 5: Line 5:
 
=== Spelling ===
 
=== Spelling ===
  
Use US English, but avoid stupid idioms like "could care less"
+
Use American English, but avoid idioms that may be difficult for non-native speakers to understand.
  
 
=== Function declarations ===
 
=== Function declarations ===
  
In case your function parameters don't fit within the defined line length use following style.
+
In case your function parameters don't fit within the defined line length, use the following style.
Indention for follow up lines is '''exactly''' one tab.
+
Indention for continuation lines is '''exactly''' one tab.
 +
 
 
<source lang="cpp">
 
<source lang="cpp">
 
void some_function_name(type1 param1, type2 param2, type3 param3,
 
void some_function_name(type1 param1, type2 param2, type3 param3,
Line 19: Line 20:
 
</source>
 
</source>
  
Sometimes with complex function declarations it might be messy to define as many parameters as possible on the same line.
+
Sometimes with complex function declarations, it might be messy to define as many parameters as possible on the same line.
 
This is acceptable too (and currently used in some places):
 
This is acceptable too (and currently used in some places):
 +
 
<source lang="cpp">
 
<source lang="cpp">
 
void some_function_name(
 
void some_function_name(
Line 41: Line 43:
 
* Try to stay under 6 levels of indentation.
 
* Try to stay under 6 levels of indentation.
 
* Add spaces between operators so they line up when appropriate (don't go overboard). For example:
 
* Add spaces between operators so they line up when appropriate (don't go overboard). For example:
 +
 
<source lang="cpp">
 
<source lang="cpp">
 
np_terrain_base  = settings->getNoiseParams("mgv6_np_terrain_base");
 
np_terrain_base  = settings->getNoiseParams("mgv6_np_terrain_base");
Line 52: Line 55:
 
np_beach        && np_biome          && np_cave;
 
np_beach        && np_biome          && np_cave;
 
</source>
 
</source>
 +
 
The above code looks really nice.
 
The above code looks really nice.
 
* Separate different parts of functions with newlines for readability.
 
* Separate different parts of functions with newlines for readability.
 
* Separate functions by two newlines (not necessary, but encouraged).
 
* Separate functions by two newlines (not necessary, but encouraged).
 
* Use a space after <code>if</code>, <code>else</code>, <code>for</code>, <code>do</code>, <code>while</code>, <code>switch</code>, <code>case</code>, <code>try</code>, <code>catch</code>, etc.
 
* Use a space after <code>if</code>, <code>else</code>, <code>for</code>, <code>do</code>, <code>while</code>, <code>switch</code>, <code>case</code>, <code>try</code>, <code>catch</code>, etc.
* When breaking conditionals indent following lines of the conditional with two tabs and the statement body with one tab. For example:
+
* When breaking conditionals, indent following lines of the conditional with two tabs and the statement body with one tab. For example:
 +
 
 
<source lang="cpp">
 
<source lang="cpp">
 
for (std::vector<std::string>::iterator it = strings.begin();
 
for (std::vector<std::string>::iterator it = strings.begin();
Line 64: Line 69:
 
}
 
}
 
</source>
 
</source>
 +
 
* Align backslashes for multi-line macros with spaces:
 
* Align backslashes for multi-line macros with spaces:
 +
 
<source lang="cpp">
 
<source lang="cpp">
 
#define FOOBAR(x) do {    \
 
#define FOOBAR(x) do {    \
Line 73: Line 80:
  
 
=== Bracing and indentation ===
 
=== Bracing and indentation ===
==== If statements ====
+
==== <code>if</code> statements ====
This rule has already been explicitly stated in the [https://www.kernel.org/doc/html/latest/process/coding-style.html Linux kernel code style] from which this code style inherits, but it will be repeated here because it seems that too many people ignore or forget about it:
+
This rule has already been explicitly stated in the [https://www.kernel.org/doc/html/latest/process/coding-style.html Linux kernel code style] from which this code style inherits, but it will be repeated here:
  
<span style="color: red">'''PUTTING THE BODY OF AN IF STATEMENT ON THE SAME LINE AS THE CONDITION IS STRICTLY PROHIBITED'''</span>
+
<span style="color: red">'''Putting the body of an <code>if</code> statement on the same line as the condition is strictly prohibited.'''</span>
  
 
Example:
 
Example:
 
<source lang="cpp">
 
<source lang="cpp">
if (foobar < 3) foobar = 45;      <-- REJECTED INSTANTLY
+
if (foobar < 3) foobar = 45;      // Bad
(foobar < 3 && (foobar = 45));    <-- OH GOD PLEASE DON'T
+
(foobar < 3 && (foobar = 45));    // Bad
 
</source>
 
</source>
  
Violating this rule will result in INSTANT REJECTION!  '''STOP DOING IT!'''
+
Violating this rule will result in '''instant rejection'''.
  
Examples of decent if statement wordings:
+
Examples of good if statement wordings:
 
<source lang="cpp">
 
<source lang="cpp">
 
if (foobar < 3)
 
if (foobar < 3)
Line 110: Line 117:
 
=== Do not be too C++y ===
 
=== Do not be too C++y ===
  
* Don't pass non-const references to functions.
+
* Don't pass non-<code>const</code> references to functions.
 
* Don't use initializer lists unless absolutely necessary (initializing an object inside a class, or initializing a reference).
 
* Don't use initializer lists unless absolutely necessary (initializing an object inside a class, or initializing a reference).
* Try to minimize the usage of exceptions.
+
* Try to minimize the use of exceptions.
 
* Avoid operator overloading like the plague.
 
* Avoid operator overloading like the plague.
 
* Don't use iterators when unnecessary.
 
* Don't use iterators when unnecessary.
 
* Avoid templates unless they are very convenient.
 
* Avoid templates unless they are very convenient.
* Usage of macros is not discouraged, just don't overdo it [http://cgit.freedesktop.org/xorg/xserver/tree/randr/rrscreen.c?id=01e18af17f8dc91451fbd0902049045afd1cea7e#n325 like X.org], it's better to use inline functions.
+
* Usage of macros is not discouraged, just don't overdo it [http://cgit.freedesktop.org/xorg/xserver/tree/randr/rrscreen.c?id=01e18af17f8dc91451fbd0902049045afd1cea7e#n325 like X.org]. It's better to use inline functions instead.
  
 
=== Classes ===
 
=== Classes ===
  
* '''Class names are PascalCase, method names are camelCase.'''
+
* '''Class names are ''PascalCase'', method names are ''camelCase''.'''
 
* Don't put actual code in header files, unless it's a 4-liner, an inline function, or part of a template.
 
* Don't put actual code in header files, unless it's a 4-liner, an inline function, or part of a template.
 
* Class definitions should go in header files.
 
* Class definitions should go in header files.
* Substantial (over 4 lines) methods should be defined outside of the class definition.
+
* Substantial methods (over 4 lines) should be defined outside of the class definition.
 
* Functions not part of any class should use <code>lowercase_underscore_style()</code>.
 
* Functions not part of any class should use <code>lowercase_underscore_style()</code>.
  
Line 130: Line 137:
 
* Doxygen comments are acceptable, but '''please''' put them in the header file.
 
* Doxygen comments are acceptable, but '''please''' put them in the header file.
 
* Don't make uninformative comments like this:
 
* Don't make uninformative comments like this:
 +
 
<source lang="cpp">
 
<source lang="cpp">
 
// Draw "Loading" screen
 
// Draw "Loading" screen
 
draw_load_screen(L"Loading...", driver, font);
 
draw_load_screen(L"Loading...", driver, font);
 
</source>
 
</source>
 +
 
* Add comments to explain a non-trivial but important detail about the code, or explain behavior that is not obvious.
 
* Add comments to explain a non-trivial but important detail about the code, or explain behavior that is not obvious.
 
* For comments with text, be sure to add a space between the text and the comment tokens:
 
* For comments with text, be sure to add a space between the text and the comment tokens:
 +
 
<source lang="cpp">
 
<source lang="cpp">
 
DoThingHere();  // This does thing    <--- yes!
 
DoThingHere();  // This does thing    <--- yes!
Line 142: Line 152:
 
DoThingHere();  //This does thing      <--- no!
 
DoThingHere();  //This does thing      <--- no!
 
DoThingHere();  /*This does thing*/    <--- no!
 
DoThingHere();  /*This does thing*/    <--- no!
DoThingHere();//This does thing        <--- Definitely not
+
DoThingHere();//This does thing        <--- no!
 
</source>
 
</source>
  
Line 148: Line 158:
  
 
* In general, adding new dependencies is considered serious business.
 
* In general, adding new dependencies is considered serious business.
* We are using C++11, boost will never be an option
+
* We are using C++11; Boost will never be an option.
  
 
=== Don't let things get too large ===
 
=== Don't let things get too large ===
  
* '''Try to keep lines under 80 characters.''' It's okay if it goes over by a few, but 90 character lines or larger are definitely unacceptable. (note: this column count assumes 4-space indents)
+
* '''Try to keep lines under 80 characters.''' It's okay if it goes over by a few, but 90 character lines or larger are definitely unacceptable. (Note that this column count assumes 4-space indents.)
 
* Functions should not have over 200 lines of code – if you are concerned with having to pass too many parameters to child functions, make whatever it is into a class.
 
* Functions should not have over 200 lines of code – if you are concerned with having to pass too many parameters to child functions, make whatever it is into a class.
* Don't let files get too large (over 1500 lines of code). Currently existing huge files (game.cpp, server.cpp, ...) are in the slow process of being cleaned up.
+
* Don't let files get too large (over 1500 lines of code). Currently, existing huge files (<code>game.cpp</code>, <code>server.cpp</code>, ) are in the slow process of being cleaned up.
  
 
=== Files ===
 
=== Files ===
  
* Files should be named using lowercase_underscore style.
+
* Files should be named using ''snake_case'' style.
* Files should have includes for everything that they depend on. Don't depend on, eg, <code>"util/numeric.h"</code> including <code><string></code>!
+
* Files should have includes for everything that they depend on. Don't depend on, eg, <code>"util/numeric.h"</code> including <code><string></code>!
* Uniqueness when compiling headers is ensured by using <code>pragma once</code> ([https://github.com/minetest/minetest/issues/6259 Accepted by all coredevs])
+
* Uniqueness when compiling headers is ensured by using <code>#pragma once</code>. ([https://github.com/minetest/minetest/issues/6259 Accepted by all coredevs])
  
 
<source lang="cpp">
 
<source lang="cpp">
Line 172: Line 182:
 
</source>
 
</source>
  
* All files should include the appropriate license header
+
* All files should include the appropriate license header.
  
 
=== Miscellaneous ===
 
=== Miscellaneous ===
  
* <span style="color: red">Do '''NOT''' use "or", use "||".</span>
+
* <span style="color: red">Do '''not''' use <code>or</code>, use <code>||</code>.</span>
* Set pointer values to ''nullptr'', not 0. Contrary to what some people may believe, ''nullptr'' ''is'' a part of the official C++11 standard.
+
* Set pointer values to <code>nullptr</code>, not 0 (<code>nullptr</code> is part of C++11).
* When using floats, add the ''f'' suffix, e.g. ''float k = 0.0f;'' and not ''float k = 0.0;''
+
* When using floats, add the <code>f</code> suffix, e.g. <code>float k = 0.0f;</code> and not <code>float k = 0.0;</code>.
 
* Do not use characters in C++ files from outside the ASCII character set.
 
* Do not use characters in C++ files from outside the ASCII character set.
* Use of Hungarian notation is very limited. Scope specifiers such as g_ for globals, s_ for statics, or m_ for members are allowed. The prefix m_ is discouraged for public members in newer code as it is a part of the class' interface, but sometimes needed for consistency when adding a member to older code.
+
* Use of Hungarian notation is very limited. Scope specifiers such as <code>g_</code> for globals, <code>s_</code> for statics, or <code>m_</code> for members are allowed. The prefix <code>m_</code> is discouraged for public members in newer code as it is a part of the class' interface, but sometimes needed for consistency when adding a member to older code.
* Don't use camelCase for local variables. Use lowercase_and_underscored instead.
+
* Don't use ''camelCase'' for local variables. Use ''snake_case'' instead.
* Don't use distracting and unnecessary amounts of object orientated abstraction. See [https://github.com/MovingBlocks/Terasology Terasology] as an example of what not to do.
+
* Don't use distracting and unnecessary amounts of object-oriented abstraction. See [https://github.com/MovingBlocks/Terasology Terasology] as an example of what not to do.
* As an addendum to the last point, don't randomly add unnecessary design patterns to your code, such as factories/providers/sources
+
* As an addendum to the last point, don't add unnecessary design patterns to your code, such as factories/providers/sources.
* In switch-case statements add break also to the last case and to default
+
* In <code>switch-case</code> statements, add <code>break</code> to the last case and to the <code>default</code> case.
* In if-else statements, put the code which becomes executed more likely first
+
* In <code>if-else</code> statements, put the code which is more likely to be executed first.
* For consistency, use American English where spellings differ (e.g. use color, not colour).
+
* For consistency, use American English where spellings differ (e.g. use "color", not "colour").
  
 
[[Category:Core Engine]]
 
[[Category:Core Engine]]
 
[[Category:Rules and Guidelines]]
 
[[Category:Rules and Guidelines]]

Revision as of 13:34, 19 August 2019

This is the coding style used for C/C++ code. Also see the Lua code style guidelines.

The coding style is based on the Linux kernel code style. Much of the existing code doesn't follow the current code style guidelines, do not try to replicate that. Use your best judgment for C++-specific syntax.

Spelling

Use American English, but avoid idioms that may be difficult for non-native speakers to understand.

Function declarations

In case your function parameters don't fit within the defined line length, use the following style. Indention for continuation lines is exactly one tab.

void some_function_name(type1 param1, type2 param2, type3 param3,
	type4 param4, type5 param5, type6 param6, type7 param7)
{
	...
}

Sometimes with complex function declarations, it might be messy to define as many parameters as possible on the same line. This is acceptable too (and currently used in some places):

void some_function_name(
	const ReallyBigLongTypeName &param1,
	ReallyBigLongTypeName *param2,
	void *param3,
	size_t param4,
	const void *param5,
	size_t param6)
{
	...
}

No more than 7 parameters allowed (except for constructors).

Spaces

  • Do not use spaces to indent.
  • Try to stay under 6 levels of indentation.
  • Add spaces between operators so they line up when appropriate (don't go overboard). For example:
np_terrain_base   = settings->getNoiseParams("mgv6_np_terrain_base");
np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher");
np_steepness      = settings->getNoiseParams("mgv6_np_steepness");
np_height_select  = settings->getNoiseParams("mgv6_np_height_select");
...
bool success =
	np_terrain_base  && np_terrain_higher && np_steepness &&
	np_height_select && np_trees          && np_mud       &&
	np_beach         && np_biome          && np_cave;

The above code looks really nice.

  • Separate different parts of functions with newlines for readability.
  • Separate functions by two newlines (not necessary, but encouraged).
  • Use a space after if, else, for, do, while, switch, case, try, catch, etc.
  • When breaking conditionals, indent following lines of the conditional with two tabs and the statement body with one tab. For example:
for (std::vector<std::string>::iterator it = strings.begin();
		it != strings.end();
		++it) {
	*it = it->substr(1, 1);
}
  • Align backslashes for multi-line macros with spaces:
#define FOOBAR(x) do {    \
	int __temp = (x); \
	foo(__temp);      \
} while (0)

Bracing and indentation

if statements

This rule has already been explicitly stated in the Linux kernel code style from which this code style inherits, but it will be repeated here:

Putting the body of an if statement on the same line as the condition is strictly prohibited.

Example:

if (foobar < 3) foobar = 45;      // Bad 
(foobar < 3 && (foobar = 45));    // Bad

Violating this rule will result in instant rejection.

Examples of good if statement wordings:

if (foobar < 3)
	foobar = 45;

if (foobar < 6) {
	foobar = 62;
	return;
}

Nested for loop exception

Special exception to the standard bracing/indent rules for nested loops: If a nested loop iterates over a set of coordinates, it is permitted to omit the braces for all but the innermost loop and keep the outer loops at the same indentation level, like so:

for (s16 z = pmin.Z; z <= pmax.Z, z++)
for (s16 y = pmin.Y; y <= pmax.Y; y++)
for (s16 x = pmin.X; x <= pmax.X; x++) {
	// ... do stuff here ...
}

Do not be too C++y

  • Don't pass non-const references to functions.
  • Don't use initializer lists unless absolutely necessary (initializing an object inside a class, or initializing a reference).
  • Try to minimize the use of exceptions.
  • Avoid operator overloading like the plague.
  • Don't use iterators when unnecessary.
  • Avoid templates unless they are very convenient.
  • Usage of macros is not discouraged, just don't overdo it like X.org. It's better to use inline functions instead.

Classes

  • Class names are PascalCase, method names are camelCase.
  • Don't put actual code in header files, unless it's a 4-liner, an inline function, or part of a template.
  • Class definitions should go in header files.
  • Substantial methods (over 4 lines) should be defined outside of the class definition.
  • Functions not part of any class should use lowercase_underscore_style().

Comments

  • Doxygen comments are acceptable, but please put them in the header file.
  • Don't make uninformative comments like this:
// Draw "Loading" screen
draw_load_screen(L"Loading...", driver, font);
  • Add comments to explain a non-trivial but important detail about the code, or explain behavior that is not obvious.
  • For comments with text, be sure to add a space between the text and the comment tokens:
DoThingHere();  // This does thing    <--- yes!
DoThingHere();  /* This does thing */ <--- yes!

DoThingHere();  //This does thing      <--- no!
DoThingHere();  /*This does thing*/    <--- no!
DoThingHere();//This does thing        <--- no!

Use STL, avoid Irrlicht containers, and no, Boost will not even be considered, so forget it

  • In general, adding new dependencies is considered serious business.
  • We are using C++11; Boost will never be an option.

Don't let things get too large

  • Try to keep lines under 80 characters. It's okay if it goes over by a few, but 90 character lines or larger are definitely unacceptable. (Note that this column count assumes 4-space indents.)
  • Functions should not have over 200 lines of code – if you are concerned with having to pass too many parameters to child functions, make whatever it is into a class.
  • Don't let files get too large (over 1500 lines of code). Currently, existing huge files (game.cpp, server.cpp, …) are in the slow process of being cleaned up.

Files

  • Files should be named using snake_case style.
  • Files should have includes for everything that they depend on. Don't depend on, eg, "util/numeric.h" including <string>!
  • Uniqueness when compiling headers is ensured by using #pragma once. (Accepted by all coredevs)
#pragma once

#include <string>

class Foo {
};
  • All files should include the appropriate license header.

Miscellaneous

  • Do not use or, use ||.
  • Set pointer values to nullptr, not 0 (nullptr is part of C++11).
  • When using floats, add the f suffix, e.g. float k = 0.0f; and not float k = 0.0;.
  • Do not use characters in C++ files from outside the ASCII character set.
  • Use of Hungarian notation is very limited. Scope specifiers such as g_ for globals, s_ for statics, or m_ for members are allowed. The prefix m_ is discouraged for public members in newer code as it is a part of the class' interface, but sometimes needed for consistency when adding a member to older code.
  • Don't use camelCase for local variables. Use snake_case instead.
  • Don't use distracting and unnecessary amounts of object-oriented abstraction. See Terasology as an example of what not to do.
  • As an addendum to the last point, don't add unnecessary design patterns to your code, such as factories/providers/sources.
  • In switch-case statements, add break to the last case and to the default case.
  • In if-else statements, put the code which is more likely to be executed first.
  • For consistency, use American English where spellings differ (e.g. use "color", not "colour").