Adium

Coding Style Guidelines

Language

Name your variables, classes, methods, functions and all other things in American English. Comments should likewise be in English, but your own local English is fine (as long as it's readable to anyone fluent in any dialect of English).

Variable names

Instance and local variables should generally be named in camelCase, with a lowercase initial letter, and no underscores. No form of Hungarian notation is to be used, ever.

Private instance variables and properties should use the class/namespace prefix, in most cases this will be AI, including an "_" underscore (this is an exception from the above rule).
It is also a good idea to put them after a @private or @protected directive

@private
    NSObject AI_privateObject;

Type and class names

Use struct or enum when allowed:

struct sockaddr saddr;
struct FSForkIOParam pb;

But not when this is discouraged (as with some Cocoa structures):

NSRect rect; //NOT struct _NSRect

Classes should be named in CamelCase, with an uppercase initial letter, and no underscores. Name your classes so that it's obvious what they belong to and what they're for. Classes should have a two letter prefix. This should be AI (for Adium). (e.g. AICamelCaseObject )

Methods should be arranged as follows:

+ (Foo *)classMethods;
+ (id)classMethodsThatCreateObjects; //e.g. new or newWithZone
- (id)init;
- (id)initWithExtraArgument:(id)extraArgument andOtherExtraArgument:(id)otherExtraArgument;
- (void)dealloc;
// Other instance methods

Don't use 'int' unless there are no qualifiers on it. All three of these declarations are correct:

int x; //no qualifiers
unsigned y; //qualifier 'unsigned'
short z; //qualifier 'short'

Selector names

Always include return type, even if it's id.

All parameter names are assumed to be inputs, unless noted otherwise. You might consider using the 'in' or 'out' keyword if it needs to be explicitly disambiguated.

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)column row:(int)row;
- (BOOL)scanUpToString:(NSString *)inString intoString:(NSString **)outString;

Private selectors/methods should use the class/namespace prefix, in most cases this will be AI, including an "_" underscore.

- (void)AI_init;

Variable Declarations

Always initialize variables at declaration time or immediately afterwards. Never use a variable's value without initializing it first.

Message line breaking

Encouraged for long messages:

//Animate the icon   
animationTimer = [[NSTimer scheduledTimerWithTimeInterval:ANIMATION_DELAY
                                                   target:self
                                                 selector:@selector(animateIcon:)
                                                 userInfo:nil
                                                  repeats:YES] retain];

(Note how the colons line up vertically in a monospaced font.)

The correct number of tabs and spaces to line up the colons can be inserted automatically by Xcode, by using the Re-Indent command in the Format menu.

Line breaking is generally encouraged for all sorts of long expressions, provided it does not reduce readability. Consider:

if (some_long_condition &&
    some_other_long_condition ||
    some_completely_different_long_condition)

over:

if (some_long_condition && some_other_long_condition || some_completely_different_long_condition) 

Braces and Whitespace

- (BOOL)textAndButtonsWindowDidEnd:(NSWindow *)window returnCode:(AITextAndButtonsReturnCode)returnCode userInfo:(id)userInfo
{
	if (returnCode == AITextAndButtonsDefaultReturn) {
                //A single comment can use double-slash to explain the following line of code
		[self gotDefaultReturn];
	} else if (returnCode == AITextAndButtonsOtherReturn) {
                /* A multi-line comment should be formatted
                 * like this and explain the code below.  Write your code so it is understandable without comments...
                 * and comment it!  This helps you and helps future programmers work with your code.
                 */
		[self gotOtherReturn];
	} else {
		[self displayError];
	}
}

Braces for method/function beginning and end go on their own lines. The last brace of an if-else chain should be on its own line, but all other braces in the chain (opening braces and closing braces) should be on the same line as the statement.

Always use tabs to indent. Never spaces. Ever.

Indent your instance variables, too.

Always use spaces around operators:

2 + 2, not 2+2
x && y, not x&&y
x << 256, not x<<256

Put a space between a keyword and the opening parenthesis:

if (a)
// not: if(a)

But not between a function name and the opening parenthesis:

printf("%s", "Hello world!\n");
// not: printf ("%s", "Hello world!\n");

Don't pad the inside of the parentheses with spaces:

if (a && b)
// not: if ( a && b )

Don't use parentheses around the argument to return (making it look like a function call):

return 0;
// not: return(0);

But it's OK for parenthesized expressions:

return ((x * y) ? 42 : [array objectAtIndex:fallback]);

Leave all blank lines (those with no visible characters) empty (not containing *any* characters). This means that a blank line should not contain any tabs or spaces.

Labels

Labels should always be on a line by themselves, and should be 1 indent to the left of the statement they apply to:

switch (answer) {
	case 42:
		printf("Found the answer! (%i)\n", answer);
}

Note that in a switch, all statements are indented two levels to allow for the case labels.

Comments

//C99 single-line comments are allowed.
/* 
 * Multi-line comments should be used whenever a comment spans
 * multiple lines, like this one.
 * Be sure the stars line up in a nice column, and that the end wing is on its
 * own line.
 * Also make sure you use a space after the column of stars.
 */

Single-line comments should not be placed on the same line as statements. We do:

//Area is pi * r-squared
area = 3.14159 * r * r;

rather than:

area = 3.14159 * r * r; //pi * r-squared

Multi-line comments should always come before the statement.

It is also recommended in some situations to use small winged comments containing the argument names when using constants in a C function call. For example:

unsigned len = [str length];
//Count UTF-8 code units (may be more than the number of Unicode code-points)
CFIndex UTF8len;
CFStringGetBytes((CFStringRef)str,
	CFRangeMake(0, len),
	kCFStringEncodingUTF8,
	/*lossByte*/ 0U,
	/*isExternalRepresentation*/ false,
	/*buffer*/ NULL,
	len,
	&UTF8len
	);

Multiple return statements

Return statements should be used at the end of methods unless there is a very good reason to do otherwise.

Example of how to avoid this:

- (NSString *)whosYourDaddy:(NSString *)inChild
{
	NSString *returnString = nil;
	if (inChild) {
		returnString = @"Alan Kay";
	}
	return returnString;
}

Use of +new

Adium does not use +new. Use +alloc/-init.

Ternary operator (foo ? bar : baz)

Allowed, and encouraged where readability is increased. Make it three lines, with appropriate indenting, if foo, bar, and/or baz are long. Always use parenthesis.

Index variables

Always unsigned unless necessary. Never use index variables for NSArrays; use NSEnumerator to iterate on those. (Only keep an index variable if you need to replace elements of an NSMutableArray.)

Numeric constants and NULL vs. nil

Always supply a fraction and an integer in any floating-point constant: 0.0, not 0. or .0. Specify type constants only if strictly necessary.

Use nil for Cocoa types, and NULL elsewhere:

- (char *)UTF8String
{
	if (UTF8String == NULL) {
		UTF8String = malloc([self length]);
        }

	if (UTF8String != NULL) {
		strcpy(UTF8String, "I am the Walrus");
        }

	return UTF8String;
}

The above is for example purposes; whenever testing against NULL/nil, use simple truth-testing (and the ! operator when appropriate):

void *buf = NULL;
size_t size = 0U, increment = getpagesize();
do {
	buf = realloc(buf, size);
	if (!buf) {
		NSLog(@"Could not allocate %zu bytes", size);
	} else {
		size += increment;
	}
} while (buf);

Otherwise, always use constants whenever possible; for example:

  • Use NSComparisonResult constants instead of -1, 0, +1 when working with -compare:.
  • Use NSNotFound when testing whether a range- or index-search method found a match.
  • When creating Core Foundation objects, use the CFAllocator constants (e.g. kCFAllocatorDefault) at all times, even when requesting the default allocator. Don't use NULL to get the default allocator.

Auto-{in,de}crement

Use prefix version whenever possible.

while (--argc) {
	printf("%s\n", *++argv);
}

Documentation style

Here's an example of how to document Adium code:

/*!
 * @brief Creates and returns an autoreleased tasty sandwich.
 *
 * This is the first paragraph. This method will create a new tasty sandwich if no previous tasty sandwich exists with the given ingredients; otherwise, it will return that previously-existing sandwich.
 *
 * This is the second paragraph. Note that this method's \a ingredients argument is an \c NSArray instance.
 *
 * @param ingredients The ingredients to put in the sandwich.
 * @return An autoreleased sandwich. May return a previously-created sandwich; if you want a completely new sandwich with no bites out of it, use <code>+[AISandwich tastySandwichWithIngredients:]</code>.
 */
- (AISandwich *)tastySandwichWithIngredients:(NSArray *)ingredients;

Credits

This document is based on Growl's HACKING.txt, with modifications for the Adium coding style.

Further Reading

This document is a "must read" Cocoa Coding Guidelines.

You may find How to Write Unmaintainable Code to be a valuable counterreference.

Also, Charles Samuels has written an excellent treatise on why tabs are better than spaces. Our own Peter Hosey has a blog post on the same topic.

Page last modified by robotive, 6 years ago