Coding Guidelines

The document below outlines our code style guidelines. If you have suggestions for things that should be clarified better, etc. please let us know. Please don't send us suggestions of the kind "I like this indenting style better, could we switch?".

The information in the document below is extremely important. If you will be contributing code or patches to Haiku, you will need to strictly follow the code style guidelines. Code which doesn't follow the guidelines below will not be accepted.

Some code doesn't match our guidelines in some places, this is mostly due to it being written before the guidelines were defined. Assistance with cleaning up incorrect code is very welcome as long as you notate in the commit that there are "no functional changes" in this patch (don't bury code changes in style fixes).

With a continuous stream of external contributions and patches we would like the Haiku code base to remain clean, uniform, and easy to read and maintain.

General

Make your code not stick out -- make it consistent with the rest of the code you are contributing to. You will see this rule stressed over and over throughout the guidelines and when submitting patches.

Indenting and white space

  • Set your editor to 4 spaces per tab.
  • Use tabs to indent blocks.
  • Lines that need broken up due to length need to have one additional indention.
  • Functions/classes in namespaces are not indented.
  • In general you use one tab per expression level, see the examples below.

First, let's use some examples to illustrate the main formatting conventions:

class Foo : public Bar {
public:
							Foo(int32);
	virtual						~Foo();
 
	virtual	void					SomeFunction(SomeType* argument);
 
	// indent long argument lists by a tab:
	virtual	const char*				FunctionLotsOfArguments(const char* name,
								const char* path, const char* user);
 
private:
		int32					_PrivateMethod();
	static	int32					_SomeStaticPrivateMethod();
 
	volatile int32					fMember;
		const char*				fPointerMember;
};
 
 
// The ':' always comes on its own line, initializers following
 
Foo::Foo(int32 param)
	:
	Bar(int32* param),
	fMember(param),
	fPointerMember(NULL)
{
	...
}
 
 
/*!	Function descriptions are using doxygen style. Please note, this is not
	a place for end-user documentation, but for documentation that helps
	understanding the code, and using the functions correctly.
*/
template<class T>
const T*
Foo<T>::Bar(const char* bar1, T bar2)
{
	...
}
static int32
my_static_function()
{
	return 42;
}
if (someCondition) {
	DoSomething();
		// Comments that only affect a single line are usually
		// written after it, and are indented by a single tab
	DoSomethingElse();
} else if (someOtherCondition) {
	DoSomethingElse();
	DoSomething();
}
 
if (someVeryVeryLongConditionThatBarelyFitsOnALine
	&& someOtherCondition) {
	// && operator on the beginning of the next line,
	// indented by a tab
	...
}
 
if (someVeryVeryLongConditionThatBarelyFitsOnALine
	&& (someVeryLongNestedConditionPart1
		|| someVeryLongNestedConditionPart2)
	&& lastPartOfSomeVeryVeryLongCondition
		!= 0) {
	// Indent one tab per expression level
	...
}
 
if (fMemberPointer->VeryLongFunctionCall(uint32 argument1,
		uint32 argument2, uint32 argument3) != NULL
	&& someOtherCondition) {
	// Function call parenthesis count as an expression
	// level thus the additional tab on the second line.
	...
 
	localVariable = AnotherLongFunction(uint32 argument1,
		uint32 argument2, uint32 argument3);
		// For this simple assignment though
		// an additional tab wouldn't help readability.
 
	anotherVariable = fSomeUselessRGBColor.alpha
		* (fSomeUselessRGBColor.red + fSomeUselessRGBColor.green
			+ fSomeUselessRGBColor.green + fOffset.blue)
		/ 3 + fBrightness;
		// This one spans more than two lines, we add
		// a tab to distinguish the expression level
		// in parenthesis.
}
 
 
for (int32 index = 0; index < count; index++) {
	DoSomething(index);
	DoSomethingElse(index);
}
 
// Omit braces for single line statements, place statement on a new line
// (but always use braces around multi-line statements)
 
if (condition)
	DoOneThingOnly(index);
 
for (int32 index = 0; index < count; index++)
	DoOneThingOnly(index);
 
// switch statement formatting
 
switch (condition) {
	case label1:
		DoSomething();
		break;
 
	case label2:
	{
		// need extra curly brackets here because of count
		// declaration
		int32 count;
		...
		DoSomething();
		break;
	}
}
 
...
	CallingSomeFunction(firstArgument * 2 + someMoreStuff,
		secondArgument, thirdArgument);
		// Indent long argument lists by a tab
...
 
	const rgb_color kNeonBlue = {10, 10, 50, 255};

Misc. formatting

  • A line must not have more than 80 columns; when wrapping a line, you usually indent one extra tab, but that can get more depending on the contents.
  • Put exactly two blank lines between functions.
  • Include a newline at every file end.

Identifiers

  • Use self-describing well chosen identifiers whenever possible. Avoid identifiers such as r (hard to search for), aMessage, theView, MyDraw (who's draw?). Avoid identifier pairs such as ProcessMessage and DoProcessMessage, AddTasks and AddTasks1. Use names such as rect, message, invokeMessage, view, targetView, DrawBorder, ProcessMessage and ProcessMessageInternals or ProcessMessageDetails, etc.
  • Classes, structs, type names, namespaces and function names start with uppercase letters and use InterCapsFormatting (no underlines).
  • variables start with lowercase letters and use interCapsFormatting.
  • member variables start with f like so:
	int32 fMemberVariable;
  • constants start with a k like so:
	const uint32 kOpenFile = 'open';
(note that this is different from the standard Be API constant names)
  • global variables are prefixed with a 'g', static variables with an 's' using the same scheme as above.
  • private methods are prefixed with an underscore.

Variable declarations

  • declare variables as local in scope where possible, avoid declaring all variables at the top of a function like you have to do in C. The advantages here are it is easier to make sure variables are properly initialized and small code snippets are easier to copy-paste around.
  • Use descriptive names, avoid reusing a single temporary variable for different purposes.
  • Use full names such as message over abbreviations such as msg. Use rect, frame, bounds over r, menuItem over mi.

Use Haiku-defined APIs, types, etc.

  • Prefer using an Haiku API utility call over "rolling your own".
  • Prefer using BObjectList over BList. BObjectList provides type-safety, optional item ownership and is designed such that additional template instantiations will not grow the code considerably.
  • Prefer BString over malloc, strdup, free, etc. for string operations.
  • Prefer BString << operators over fixed size buffers and sprintf.
  • Prefer using types defined in SupportDefs.h such as int32, uint32, over int, long, etc. Use status_t over int, int32 where errors are returned. Use off_t over int64 where appropriate.

Comments

  • Comment your code properly.
  • Prefer C++ style comments.
  • Comment properly but not excessively. (some examples of excessive commenting:)
	...
	index++; // increment the index
	...
 
	...
	/* InitProgress
	 *
	 */
	void
	InitProgress(int param1)
	{
	...
  • Prefer commenting over and under the commented line (over when a comment relates to a chunk of code, under and indented by a tab when it relates to one specific line.
	// the trash window needs to display a union of all the
	// trash folders from all the mounted volumes
	// (comment about a block of code)
	BVolumeRoster volumeRoster;
	volumeRoster.Rewind();
	BVolume volume;
	while (volumeRoster.GetNextVolume(&volume) == B_OK) {
		if (!volume.IsPersistent())
			continue;
		...
	}
	...
	BPoseView::WatchNewNode(&itemNode,watchMask, lock.Target());
		// have to node monitor ahead of time because
		// Model will cache up the file type and preferred
		// app (comment about the above line)
  • Avoid comments on the same line that create long lines (prefer comments on a separate line in general
	...
	if (this < is && a < very && long != condition) { // ...
	...
	if (this < is && a < very && long != condition) {
		// this comment is about the long condition
		// above and is much easier to read!
	...
  • Do not annotate your comments with your name or initials -- when your patch gets submitted, SVN will have your name in the checkin log. Anyone can identify your code that way.
  • Avoid expressing your sentiments in comments, do not include comments like this:
	// this is a hack!
Instead explain why you consider the respective code a hack:
	// the following code is fragile because it doesn't
	// handle overflows properly

License and Copyright

  • The preferred format for source file copyright and license notices is:
/*
 * Copyright 2004-2007 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Jonathan Smith, optional@email
 *		Developer Name, optional@email
 */
In case everything is copyrighted to "Haiku, Inc." and authors are listed in lexicographic order by last name.
  • Public headers should always be copyrighted to "Haiku, Inc." and don't list any authors.
  • In case you prefer to keep the copyright to yourself, the license header should look like the following; multiple authors can be listed like in this example:
/*
 * Copyright 2007 Jane Doe, optional@email
 * Copyright 2003-2005 Some Developer, optional@email
 * All rights reserved. Distributed under the terms of the MIT License.
 */
  • In some cases you might have to extend the copyright list of an existing file. Instead of using the alternative scheme like in the latter example the preferred method is to add a copyright line for "Haiku, Inc." and then list authors like in the first example.
  • In header files, there is no blank line between license text and header guard.
  • After the copyright header (including the header guard in header files), there are exactly two blank lines before the rest contents.

Dead code and Debugging code

  • Do not leave dead, commented or #if 0'ed code behind just because you are not sure about your contribution. Your change should be top quality to begin with, improving the code you are replacing. Should there be a reason to back your change out or used for a reference, this can be done using the source control tools.
  • Do not leave simple commented out debugging printfs behind. These days bdb does a great job eliminating the need for most debugging printfs. Use ASSERTs for debugging purposes. Include debugging code in #if DEBUG blocks. Make sure debugging code compiles (make sure your change doesn't break existing debugging code, if it does, fix the debugging code as a part of the change) without warnings and stays correct. Use all the other tools from Debug.h to your advantage.

Miscellaneous

  • Use new-style casts (dynamic_cast, static_cast, const_cast, reinterpret_cast) over old-style.
  • Use const properly.
  • Prefer stack-allocated objects over heap-allocated ones whenever possible.
  • Use AutoLock, etc. for all locking and other resource acquisition, don't use Lock() and Unlock() on a BLocker directly. Don't use BAutolock, use the AutoLock template instead.
  • Don't assign in if, while statements:
	if ((err = entry.GetRef(&ref)) == B_OK)
		...
  • Avoid using assignments in while loops, don't use:
	BMenuItem* item;
	int32 index = 0;
	while ((item = ItemAt(index++)) != NULL) {
		...
Instead use wordier but as efficient for:
	for (int32 index = 0; ; index++) {
		BMenuItem* item = ItemAt(index);
		if (item == NULL)
			break;
		...
  • Don't check for NULL before delete and free:
	// wrong
	if (fIcon != NULL)
		delete fIcon;
 
	// wrong
	if (fIconBuffer != NULL)
		free(fIconBuffer);
  • Don't put parentheses around return values:
	// wrong
	return (fList.ItemAt(index));
  • Don't put redundant parentheses in if statements:
	// wrong
	if ((a == 3) && (b != 4))
		...
  • However, use parenthesis when checking bitmasks, and always use this form:
	if ((a & 3) != 0 && (b & 4) == 0)
		...
 
	// wrong - C/C++ operator precedence works differently
	if (a & 3 && xyz)
		...
  • Always use boolean conditions, instead of pointer/integer logic:
	// This is how it should look like:
	if (pointer != NULL || anotherPointer == NULL || intValue != 0)
		...
 
	// wrong - don't use the following style
	if (pointer || !anotherPointer || intValue)
		...
  • Use inlines sparingly.
  • Use constructor initializer lists over initializing members inside the constructor body
  • When you return in an if-block, don't use 'else' -- it's superfluous, and reduces the clarity of the code:
	// This is how it should look like -- notice, no 'else':
	if (something) {
		...
		return true;
	}
	if (somethingElse) {
		...
		return true;
	}
	return false;
 
	// Wrong - don't use code like below:
	if (something) {
		...
		return true;
	} else if (somethingElse) {
		...
		return true;
	} else
		return false;
  • Use built-in false/true instead of FALSE/TRUE #defines.
  • Alphabetize #include statements, group "includes" and <includes> separately.
  • While the header that belongs to a source file should be included first to ensure self containment, all other headers are specified from most general (POSIX) to most specific (local directory). In order to alphabetize them, please group them by API origin, like (but without the comments, of course):
#include "ThisClass.h"
 
// POSIX API headers
#include <stdio.h>
#include <string.h>
 
// Haiku API headers
#include <File.h>
#include <OS.h>
 
#include <PrivateHeader.h>
 
#include "OtherLocalHeaders.h"
  • Don't use <pathname/include.h> if they aren't necessary; (like for <sys/stat.h>).
  • Use NULL instead of 0 for pointers.
  • Avoid gotos.
  • Don't use constructor call syntax for initializing pointers, etc. to NULL like this: