Skip to content

Code Format and Commenting

KimBurgess edited this page Mar 28, 2012 · 2 revisions

To aid in maintaining consistency across all of the common libraries in formatting, naming, logic structure, and internal documentation style, the following guidelines should be adhered to when contributing or modifying any code.

The Linux kernel coding style has been used as a base for these guidelines.

Layout and Formatting

Tab Stops

Tab stops should be set at 4 characters. Tab stops should use the tab character. Do not use spaces.

Column Width

Column width is to be set to 81 characters.

Indentation

Each level of indention is to be the same width as a single TAB character. Although indentation does not effect logic structure within the NetLinx language, it is imperative that this is maintained for code readability.

Spaces

Where possible, excess whitespace should be avoided. The exception to this is where it provides a logical separation between values.

Do not add spaces around (inside) parenthesized expressions. The following is a bad example

foo_bar( x )

Use one space around (on each side of) binary operators, such as any of these:

=  +  -  <  >  *  /  %  |  &  ^  <=  >=  ==  !=

but no space before the postfix increment & decrement unary operators:

++  --

When calling functions, no space should be inserted between the function name and opening parenthesis of the argument list, however arguments should be separated by a comma followed by a single space.

String concatenation should follow the same spacing form as function argument lists described above.

Examples

For Loops
integer i
for (i = 0; i < 10; i++) {
    foo_bar(i * 10, 'abc')
}

is preferable to

integer i
for ( i = 0 ; i < 10 ; i++ ) {
    foo_bar ( i * 10, 'abc' )
}

or

integer i
for(i=0;i<10;i++){
    foo_bar(i*10,'abc')
}
String Concatenation
char[] x = "'foo', $20, 'bar'"

is preferred to

char[] x="'foo',$20,'bar'"
Functions
foo_bar(i * 10, 'abc')

is preferable to

foo_bar ( i * 10 , 'abc')

or

foo_bar(i*10,'abc')

Line Breaks

Conditional Statements

Conditional statements should always split the condition and the action into separate lines. For example

if (x == y) {
    foo_bar(z)
}

should be used instead of

if (x == y) foo_bar(z)

Complex Conditionals

For complex conditionals which expand beyond the defined [CodeFormatAndCommenting#Column_Width column width] each condition is to be placed on a new line and the line indented by a TAB character further than the parent.

define_function foo_bar()
{
    ...
    if (x > y &&
        x <= z &&
        w <> x) {
        // Do something
    }
    ...
}

Argument Lists

If a function requires an extended argument list which causes the invocation to expand beyond the defined [CodeFormatAndCommenting#Column_Width column width], each argument should be placed on it's own line and indented by two tab characters beyond the current level of indentation.

uber_foo_bar(arg0,
        arg1,
        arg2,
        arg3,
        arg4,
        arg5)

If the arguments can fit within the column width they invocation should be written as a single line

foo_bar(arg0, arg1)

Array Assignment

When assigning a list a values to an array, each entry should appear on its own line:

char tmp[] = {
    'a',
    'b',
    'c'
}

rather than

char tmp[] = {'a', 'b', 'c'}

Brace Placement

Function Definitions

The first line of a function definition should include the required preamble, function name the parameter list. The open brace of the function scope is to be placed on the following line.

define_function char foo_bar (integer a, char b)
{
    // Return something
}

Event Handlers

Netlinx event handlers are to be formatted in the same way as function blocks. That is, the opening brace is to sit on a line by itself following the event definition.

button_event[device, 0]
{
    push:
    {
        // Do push event guff
    }
    release:
    {
        // Do release event
    }
}

Non-Function / Event Statement Blocks

All other statement block are to have the opening brace appear on the same line as the block's opening statement.

if (x > y) {
    // Do something
}

Naming, Logic and Higher Techniques

Function Names

Functions that have analogs to built-in functions in other languages and / or seem like they should be a built-in in regards to standard use of NetLinx in working code should probably be named with similar names (in the former case) and use short names (example: trim). Those that are more specialized should be prefixed with the name of the library in which they are in followed by an underscore.

Function names which utilise multiple component words should separate the words with an underscore.

Variable Names

Do not use cute names like thisVariableIsATemporaryCounter. Instead it should be called tmp, which is much easier to write, and remains easy to understand.

However, while mixed-case names are frowned upon, descriptive names for global variables are a must. If a global variable named something similar to foo is found anywhere in the repository the commit logs will be traced to find the original author of that line. This person will then be tracked down and slapped with a wet fish. Repeatedly.

Global variables (to be used only if you really need them) need to have descriptive names. If you have a function that counts the number of active users, you should call that count_active_users() or similar, you should not call it cntusr().

Encoding the type of a function into the name (so-called Hungarian notation) is brain damaged - the compiler knows the types anyway and can check those, and it only confuses the programmer.

Local variable names should be short and to the point. If you have some random integer loop counter, it should be called i, or similar. Calling it loop_counter is non-productive, if there is no chance of it being misunderstood. Similarly, tmp can be just about any type of variable that is used to hold a temporary value.

Function Parameter Names

Sticking with the 'lazy programmer approach' of using short names, functions in which the argument type is implied (ie. sqrt()) should use a single character variable name - x. For functions requiring multiple arguments, or where the parameter may not by obvious, descriptive names (which adhere to the above variable naming guidelines) should be utilized.

Line Termination

Although the NetLinx compiler permits the use of a semi-colon (;) to signify line termination this should not be used, as lines are automatically terminated.

Commenting

Comments are good, but there is also a danger of over-commenting. NEVER try to explain HOW your code works in a comment: it's much better to write the code so that the working is obvious, and it's a waste of time to explain badly written code.

Generally, you want your comments to tell WHAT your code does, not HOW. Also, try to avoid putting comments inside a function body: if the function is so complex that you need to separately comment parts of it, you should probably go back to chapter 6 for a while. You can make small comments to note or warn about something particularly clever (or ugly), but try to avoid excess. Instead, put the comments at the head of the function, telling people what it does, and possibly WHY it does it.

The preferred style for long (multi-line) comments is:

/*
 * This is the preferred style for multi-line
 * comments.
 * Please use it consistently.
 *
 * Description:  A column of asterisks on the left side,
 * with beginning and ending almost-blank lines.
 */

To save space you can put a comment on one line:

/* This comment takes up only one line. */