less_retarded_wiki/programming_style.md
2024-03-19 16:01:03 +01:00

7.2 KiB

Programming Style/Code Formatting

In majority of cases a programming language lets the programmer choose the visual/surface style in which to write the code -- one may choose names for variables, indent and align commands in a convenient way, insert comments and so on. This gives rise to various styles -- typically a programmer will have his own preferred style, kind of like handwriting, but once he works in a team, some compromise has to be found to which everyone must conform so as to keep the code nice, consistent and readable. Some project, e.g. Linux, have evolved quite good, tested and de facto standardized styles, so instead of inventing a custom style (which may not be as easy as it sounds) one may choose to adopt some of the existing styles.

There exist automatic code formatters, they are often called code beautifiers. But not everything can be automatized, for example inserting empty spaces to separate logically related parts of a sequential of code.

TODO: moar

Here we propose a programming style and C code formatting you may use in your programs. { It's basically a style I personally adopted and fine-tuned over many years of my programming. ~drummyfish } Remember that nothing is set in stone (except that you mustn't use tabs), the most important thing is usually to be consistent within a single project and to actually think about why you're doing things the way you're doing them. Keeping to the standard set here will gain you advantages such as increased readability for others already familiar with the same style and avoiding running into traps set by short-sighted decisions e.g. regarding identifiers. Try to think from the point of view of a programmer who gets just your source code without any way to communicate with you, make his life as easy as possible. Also suppose he's reading your code on a calculator. The LRS style/formatting rules follow:

  • Respect the LRS design principles (KISS, no OOP, avoid dependencies such as stdlib etc.).
  • Indentation: use two spaces, NEVER use tabs. Why? Tabs are ugly, tricky (look the same as spaces) non-standard behaving characters (behavior is dependent on editor and settings, some processors will silently convert tabs and spaces, copy-paste may do so also etc.), they don't carry over to some platforms (especially paper), some very simple platforms may not even support them; your source will contain spaces either way, no need to insert additional blank character.
  • Limit source code width to 80 columns or similar value. Keep in mind the source may be edited on computers with small screens (like old thinkpads, especially within context of LRS) with a screen split vertically.
  • Write opening and closing curly brackets on their own lines, in the same columns, e.g.:
if (a == b)
{
  doSomething();
  doSomething2();
}
else
{
  doSomethingElse();
  doSomethingElse2();
}
  • Omit curly brackets if you can (e.g. with a single command in the block). However write them where not doing so is likely to cause confusion or syntax errors.
  • Use normal brackets to make precedence and intention clearer even if they would be unnecessary, don't flex by writing an expression with confusing precedence that saves 4 text characters. For example it may be better to write (a && b) || c rather than a && b || c.
  • identifiers/names:
    • Use camelCase for variables and functions (e.g. myVariable). Global and big-scope variables should have a greatly descriptive, self-documenting name, even if long (e.g. getTicksSinceStart, countryAreaKMSquared), local/short-scope identifiers can be shorter (e.g. argBackup within a single function), even just one letter (e.g. i within a single loop).
    • Use CapitalCamelCase for data types (e.g. ImaginaryNumber, GameState etc.).
    • Use ALL_CAPS_SNAKE_CASE for macros and constants (e.g. PI, MIN, LOG_ERROR, ...).
    • It is advised that for your project you come up with a three letter namespace prefix that will come in front of your global identifiers. (E.g. small3dlib uses the prefix S3L_, SDL uses SDL etc.). If you choose a prefix XYZ_, prepend it to all global identifiers, it will prevent name clashes and help readability, e.g. when writing a renderer you will export identifiers such as XYZ_init, XYZ_draw, XYZ_setPixel, XYZ_Model3D etc. Do NOT use the prefix in local variables (inside functions, loops etc.).
    • Prefix private global identifiers with _, e.g. _tmpPointerBackup; with the above mentioned namespace prefix this will look e.g. like this: _XYZ_tmpPointerBackup.
  • Use spaces to make code more readable, so e.g. int x = 10, y = 20; instead of int x=10,y=20;, write space between if and its condition etc.
  • Use verbs for functions, nouns for variables and keep consistency, e.g. a function should be named getTimeMS while a variable will be named timeMS.
  • Name from general to specific, e.g. getCountryTimezone and getCountryCapital instead of getTimeZoneOfCountry, getCapitalOfCountry etc. This helps with code completion systems. It's not always exactly clear, you may also decide to go for countryGetTimezone etc., just keep it consistent.
  • Filenames: always use only lowercase letters (some older systems just know one case, don't confuse them), either use camel_case.ext or nocase.ext.
  • Use blank lines to logically group relevant lines of code. E.g.:
int a = x;
char b = y;

c += 3 * a;
d -= b;

if (c < d)
  a = b;
  
doSomething(a);
  • Each file shall have a global comment at the top with at least: short description of the file's purpose (this is almost always missing in mainstream), short documentation, license, the author(s) and year of creation.
  • Use comments to make your code better readable and searchable with things like grep (add keywords to relevant parts of code, e.g. comment // player shoots to code implementing player shooting etc.). Use doxygen style comments if you can, it costs nothing and allows auto documentation.
  • TODOs and WIPs are good.
  • Don't use enums, use #defines.
  • Global variables are great, use them. Long functions are fine. Repeating yourself may also be fine if the alternative is too complex.
  • Adhere to C99 or C89 standard.
  • Try to not create many source files, many times your project can very well be in a single file which is the ideal case. Create header only libraries If you have multiple files, keep them in the same directory and try to have just a single compilation unit (only one .c file with several .h files). Try to make files no longer than 10k lines.
  • Use the LRS version numbering system.
  • Never use non-ASCII characters in your source code. Just don't, there is basically never any need for it.

Example

Here is a short example applying the above shown style:

TODO (for now see LRS projects like Anarch, small3dlib, SAF etc.)