This document is intended to provide a base standard for all languages derived from C and C++ that we work with at Appcelerator, allowing us to write clean, consistent-looking, readable code. Due to the lack of well-defined common C coding standards, we have grown our own from scratch, as opposed to the Java and Objective-C standards, which are based on well-defined existing standards that have modifications made to them.
This document does not include platform- or product-specific conventions for C or C++.
The following is a set of standard formatting and naming conventions which we expect to be followed for C or C++ source code.
We do not enforce column width. However, you should make a best effort to keep your source readable on 15" monitors, which have approximately 200 columns (based off of Andale Mono 12pt.)
- Indentation is done in tabstops (
\t) to allow for configurable spacing in modern IDEs. For the purposes of all indentation, one tabstop is considered to be 4 spaces.
- Consecutive lines of whitespace should be avoided within blocks of code, but may be used to separate logical sections of definitions.
- Whitespace should be used to separate logical code blocks. Use your best judgement.
- Blocks which are used solely for scoping must be both preceded and followed by one line of whitespace.
Whitespace should be placed between function definitions.
- Comments should be preceded by a line of whitespace, unless they are inline.
- Complete flow control statements (
switch) should be followed by whitespace.
returnstatements should not be followed by whitespace.
- All alignment must be on tabstops.
There are two types of comment styles: Comments formatted for internal documentation, and comments formatted for documentation generation.
- Comments must follow the general formatting rules below, except for where they conflict with the documentation generation rules (appledoc requires that the comment open with
/**on a single line to be processed, for example, and some may not allow for leading splats or require other keywords.)
- Commenting style:
- Methods or functions are documented with
/* ... */, where each line has aligned splats
- Code is documented with aligned
- Commented-out code is documented with
/* ... */
- Methods or functions are documented with
The following words are not allowed in comments:
- workaround (exception: In conjunction with an explanation of an issue we have no control over)
- "implement later" or other TODO-equivalent statements (use TODO)
- Any words you would not say in front of a nice grandma
- "Why do we...?" (check the blame, ask the original committer, and document or remove the questionable code)
- Words or phrases which could be considered as detrimental to the platform
In addition it is expected that all of your comments will contain correct spelling (and reasonable grammar for the intent of the comment)
When to write comments
- Exposed API (public, protected, or a C function in a header file)? Write a comment, and make sure the docgen can pick it up.
- Done something strange? Write a comment.
- Need to write pseudocode or logic flow? Write a comment.
- Handling a unique edge case? Write a comment.
- Is your code a platform "workaround" of some kind? Write a comment.
- Did you have to ask a colleague about the intent of code they wrote? Write a comment for it.
- When in doubt? Write a comment.
When not to write a comment
- If your comment has absolutely nothing useful to say about the source, don't write a comment.
- If your comment is redundant, don't write a comment.
- If your comment explains something obvious in the source, don't write a comment.
- Closing braces must be on their own line, and followed by whitespace.
- Exception: Closing braces immediately followed by another closing brace are not followed by whitespace.
- Opening braces must be on their own line, aligned with the previous statement.
- Opening braces should not be followed by whitespace.
NEVER use "using namespace x". This include "std" in C++
Namespaces should follow the following declaration/definition ordering, with each section separated by whitespace:
- typedefs (including
- function declarations
- inlined functions
- class information
- implementation (inline & template)
When using a namespace in a implementation file, use the following style:
You are expected to include standard
#ifndef / #define / #endifguards in your header files, where the macro is named:
- Headers must be
extern "C"if intended to be interoperable with C code.
- Headers should contain logically grouped macros, typedefs, classes, and function definitions only, which are intended to be used by code from outside of the implementation file.
- Exception: Headers must also contain implementations for templated code, as required by C++.
- Exception: Headers must contain implementations for inline functions, but these should be used sparingly. Remember that
inlineis only a compiler hint.
- Headers mustcontain an up-to-date copyright notice. If you modify a header with an incorrect copyright date, you are expected to update it.
- If you modify the source for a 3rd party library, you are expected to include a copyright header which mentions that "some modifications" were performed by Appcelerator, and those changes are available under the same license as the original source (or a compatible license).
Order of declarations
Headers should have their definitions/declarations ordered in the following way (with
namespace-contents as above), with whitespace between sections:
- copyright notice
- header include check
- 3rd party
- namespace-contents (same ordering of contents,
The preprocessor deserves its own detailed section. However, you are discouraged from using the preprocessor except where absolutely necessary.
Macro names must:
- Be in all caps
- Have words separated by underscores
- Be descriptive
All preprocessor directives must not be indented (start at column 0) although their contents may be aligned with surrounding code.
The include Directive
- For system headers:
- For project/3rd party headers:
Do not define global constants with
const variables only, and ideally constants are in a
namespace as well (when writing C++.)
The define Directive
- Do not include a semicolon at the end of a
#defineonly for situations in which you cannot use
inlinefunctions. Such examples may include:
DEBUGor other conditional-compilation checks
- Function-like calls which cannot be easily abstracted into functions (such as our Objective-C macro
- Function generators (such as
setXpairs, or defining a function which returns a constant value)
#definestatements which perform any sort of inline operation must be enclosed in parenthesis
#definestatements are expected to be formatted according to the usual rules, with the first statement of the
#definenot being indented.
- Conditionals should have their contents aligned with surrounding code, or if the conditional does not have surrounding code, their first line should not be indented.
- All flow control statements must have a logical block associated with them (no single-statement if)
Checking for validity of a pointer or value directly is allowed:
if (ptr != NULL)are both acceptable. Where clarity is a primary concern (such as compound conditionals) the latter is preferred.
casemust have a logical block associated with it unless it is fallthrough-only.
default:should be the final case of your
- Corollary :
defaultshould never be a fallthrough statement. Even if it does nothing, it should consist of a
- Corollary :
casemust have their final line be the comment
// FALLTHROUGH, or have the comment inline if they are fallthrough-only.
casestatements which early-
returndo not have to end with a
goto is necessary sometimes but each usage must:
- Be preceded by a comment indicating the necessity of
- Use a well-named label
goto when it is absolutely required and you have no other option.
Looping constructs follow all the rules for flow control, as far as placement of braces and organization of multi-line conditionals.
Whether or not to use inline variable declarations for any looping construct (but especially for your
for loop iterator(s)) is at your discretion.
- Function names should not be camel-case; they should have words separated by _.
- No space between the method name and opening parenthesis
- There must be a single space (or newline) between a
,and the next variable in the arguments list
- Every function is expected to have a declaration. Functions which are to be exported or otherwise publicly available are to be declared in an associated header file; all other functions are declared in the implementation.
- Declarations should include both a type and a name for all parameters.
- Functions which take no arguments do not need to be declared as
f(void); can be
- Functions should be named as "actions" rather than things (
return a compound statement should have that expression wrapped in parenthesis.
- Variables should not be camel-case; they should have words separated by _.
- Variables should have descriptive names; the exception is for pure iterators, which are allowed to be
i, j, k.
- Variables must be defined at the beginning of a block.
- Only one variable should be defined per line (no comma operator when defining variables.)
- Only one variable should be assigned to per line (no chained
- Variables should be named as "things" rather than actions or gerunds.
- Variable types should follow these rules:
- Pointer types should have the * after the type, followed by a space
- Reference types should have the & after the type, followed by a space
- Array types should have the
after the variable name
- Array types should be preferred over pointer types where the intended use of the object is as an array.
enumconstructs should be capitalized camel-case, and placed on the same line as the closing brace.
- Names of type constructs should be capitalized camel-case
- Do not use
structas a C++ construct.
structshould be used only in the way that it is defined by the C specification.
- In particular, do not include functions as part of your
structsare POD (plain old data). Do not use the
publicaccess specifier in your structs, either.
- In particular, do not include functions as part of your
unionshould only be used as part of a
The name of the type associated with the construct should be on the same line as the closing brace, not on its own line.
- Always put a space both before and after binary operators.
- Always put a space before any unary prefix operators, unless immediately preceded by a parenthesis.
- All casts (C-style and C++
x_cast<>()) are considered unary prefix operators for this purpose.
- All casts (C-style and C++
- Always put a space after any unary suffix operators, unless they are immediately followed by a
- Always place parenthesis around compound statements where order of operations may be ambiguous (such as mixing binary and arithmetic operators.)
Expressions spanning multiple lines should have their continuing lines indented to one tabstop beyond the initial
- Prefix increment/decrement is preferred over postfix increment/decrement.
- Make a best effort to avoid usage of these operators in compound statements.
Usage of ternary is discouraged, but it is often useful for certain cases (such as assignment or return value based on a condition.) When using ternary, you should:
- Consider ternary to always be a compound statement in and of itself
- Place any compound statements within parenthesis
- Treat both the
:characters as binary operators
- Avoid obvious side-effects within ternary, unless they are intended.
A special word on operator overloading for C++: Avoid operator overloading. Overloading operators leads to interesting scenarios such as this one:
In the case where you absolutely must overload an operator (such as placement
new(), incrementing enumerators, or creating a functor) then you are expected to provide ample documentation justifying your folly and make every effort possible to prevent other developers from committing crimes such as the above example.
An additional note: You must define both
+(int) when overloading increment (and the equivalent operators when doing decrement) and the definitions must be identical.
These rules are to be applied on top of any C rules described above. If there is a conflict then the rule described in the C++ section takes priority.
- use .h, .c and .cpp only
- Members and methods should be order by public, protected and then private
- All members and methods should be within a access level block
- Private members should be in a access level specifier (IE: don't rely on the default class access level)
Access identifiers within a class should be aligned with the "class" in the declaration. IE:
- Permissions should be strict by default and opened up as needed
- Inline methods should be defined in a implementation file and not in the header or class declaration.
- Keep implementation outside of class declaration. The class declaration should be seen as a interface that you can read over quickly in order to understand how to use it.
- If class is meant to be derived from, make sure to include a virtual destructor (a destructor defined for this purpose does not fill the need for the "rule of three")
- Respect the rule of three ("always override operator=, destructor, and copy constructor if you override any").
- Comment if a method is static in method comment within the implementation file
*Remember that virtual methods have time and cost (IE: just think when using them)
- Multiple inheritance should be avoided in most cases. Inheritance of a single normal class and multiple interfaces (pure virtual class) is allowed. Keep in mind that when using multiple inheritance you are going to draw strong questions and concerns regarding the design - be prepared with very good answers.
- "new" should be used over malloc when possible
- Shouldn't really need to be called out, but NEVER mix malloc/delete and new/free
- Be const correct within reason. It can be a huge pain in the ass but it's less painful in the long run.
- Try to avoid const_cast<>()
- Use function overloading rather than name variants if possible (IE: add() with overloaded versions rather than addInt, addFloat, etc)
- Remember that STL can be expensive. Dont use a sledgehammer to drive a nail into the wall
You are expected to use a C99-compliant compiler for all C and C++ code.
Although you may use a (partially) C+11-compliant compiler, do not use C+11 features in any code.
BOOST is illegal. If you make a commit which uses BOOST (and is not a 3rd party library that depends on BOOST, and even then...) you are fired.
Nonstandard extensions such as blocks or GCC-specific macros/definitions/keywords should not be used unless you are writing code which is intended to be used with compilers supporting these features only and do not intend to port the source to, or use on, other platforms.
If you must use these features, place them within the appropriate preprocessor conditional blocks.
C++ FQA familiarity
When writing C++, you may want to maintain a level of familiarity with the FQA (Frequently Questioned Answers) to avoid grammar ambiguities and recognize inappropriate usage of features. This is especially true when using the FAQ Lite as a reference.
Writing professional, enterprise-level code is not an obfuscation contest. Do not use aggressive, weird tricks for optimization or other confusing-looking code without first:
- Considering all other possible options
- Documenting it
Use your best judgement as to what constitutes "clear code" and expect a general consensus over what constitutes that particular style as the source base evolves.