This document is not complete. If a guideline for a particular format is missing, follow the style of existing code (prefer using Haiku sources as a reference for this). If you have suggestions for things that should be clarified better, etc. please let us know [0]. Please don't send us suggestions of the kind "I like this indenting style better, could we switch?".
Some code doesn't match our guidelines in some places, due mainly to time constraints. Help with cleaning up the code is very welcome.
Rather than advocating a given coding style, the main goal here is code consistency - after a stream of external contributions and patches we would like the Haiku code base to remain clean, uniform, 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
- Use tabs to indent blocks. Set your editor to 4 spaces per tab.
- The Haiku indenting style is close to the K&R [1] style.
- Functions/classes in namespaces are not indented.
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 *);
// you may omit argument names if they don't help
// documenting their purpose
virtual const char * FunctionWithLotsOfArguments(const char *name,
const char *path, const char *user);
// indent long argument lists by a tab
private:
int32 _PrivateMethod();
static int32 _SomeStaticPrivateMethod();
int32 fMember1;
int32 fMember2;
const char * fMember3;
};
Foo::Foo(int32 param)
: Bar(2 * param),
fMember1(param),
fMember2(param - 1),
fMember3(NULL)
{
...
}
template<class T>
const T *
Foo<T>::Bar(const char *bar1, T bar2)
{
...
}
if (someCondition) {
DoSomething();
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) {
// operator || in the nested condition is indented
// by a tab
...
}
for (int32 index = 0; index < count; index++) {
DoSomething(index);
DoSomethingElse(index);
}
// omit braces for single line statements, place statement on a new line
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
- Try to wrap your code to a reasonable width of 80 - 90 columns.
- Put exactly two newlines 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 fImAMemberVariable;
- constants start with a k like so:
const uint32 kOpenFile = 'open';
- (note that this is different from the standard Be API constant names)
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 BeOS-defined APIs, types, etc.
- Prefer using a BeOS 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 volRoster;
volRoster.Rewind();
BVolume volume;
while (volRoster.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.
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)
break;
...
- Don't check for NULL before delete and free:
// wrong
if (fIcon)
delete fIcon;
// wrong
if (fIconBuffer)
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))
...
- Use inlines sparingly.
- Use constructor initializer lists over initializing members inside the constructor body
- Use built-in false/true instead of FALSE/TRUE #defines.
- Alphabetize #include statements, group "includes" and <includes> separately.
- Don't use <pathname/include.h> (<sys/stat.h> is an exception).
- Use NULL instead of 0 for pointers.
- Avoid gotos.
- Don't use constructor call syntax for initializing pointers, etc. to NULL like this:
// wrong
BView *view(NULL);
- Use the more traditional assignment:
BView *view = NULL;
- (Don't confuse this with the appropriate use of constructor calls for stack based objects and objects allocated with new).
- When comparing a function call result/variable with a constant, don't place the constant on the left side of the comparison like this:
if (B_OK == file.InitCheck()) // don't use this style
...
- Programmers use this to make sure they do not end up assigning instead of comparing. The notation is a bit unusual though, placing the more important function call/variable to the less prominent position on the right. Haiku does not use this notation, a mistaken assignment will get caught by a warning.
- Prefer C-style headers (string.h, stdlib.h) over their C++ equivalents (cstring, cstdlib): Haiku's headers are generally C++ safe, and don't need this workaround.