Faculty of Applied Science and Engineering, University of Toronto
CSC181: Introduction to Computer Programming, Fall 2000
Code Conventions

Contents

Introduction

Comments

Names

General Formatting

Formatting Statements, Declarations and Definitions

Programming Practices


Introduction

Why Have Code Conventions

The most compelling reason for you, as a student, to use code conventions, is that they improve the readability of your code.

Readable code can help you (and your teammates, if you're working on a team) understand your code better, and this is especially crucial when you try fixing your code, an ongoing process which takes almost 80% of the time for a programming assignment.

Perhaps more importantly, readable code helps the markers understand it. It is hard to convince a marker that your code is correct (or partially correct) if it cannot be understood in the first place.

Acknowledgements

This document borrows heavily from Code Conventions for the Java(TM) Programming Language, which is publicly available from Sun Microsystems' Java Web site and Java Guidelines by lecturer Paul Gries, which is included in the CSC148 Course Handbook, 6th ed., from the Department of Computer Science, University of Toronto.

This document was compiled and is maintained by Ray Ortigas. Comments should be sent to rayo@dgp.toronto.edu.


Comments

Comments help other programmers understand your code. Sometimes these are people on your programming team, people who have replaced you, or complete strangers.

Even if you're programming alone, comments can help you understand code that you may have previously understood, but do not understand now. There is nothing more frustrating than trying to re-understand code that you originated.

Generally, you should place comments before the code being documented. The following sections describe how to write particular types of comments.

Header Comments

Each source file should begin with a comment which contains the following items:

  • The assignment for which this file is relevant.
  • The name of this file.
  • A short description of the file's contents.
  • A list of the authors and their school e-mail addresses.
Example
/*
 * Faculty of Applied Science and Engineering, University of Toronto
 * CSC181: Introduction to Computer Programming, Fall 2000
 *
 * Assignment: 1
 * File: integerset.h
 * Contains: Interface for IntegerSet class.
 * Author: Foo Bar (barf@ecf.toronto.edu)
 */

Class/Struct Comments

Class comments should be short, describing the purpose of the class, and need not mention available functions/methods. They should not contain any implementation details, either. Users typically won't have access to the code inside your functions. They'll only see the class and its interface. Therefore, it doesn't help at all-it even hurts-to discuss private variables and functions, algorithms used, and so on. Even if they can see the internal details, it is very likely that they'll want to ignore these. In a project with tens of thousands of lines of code, it is necessary as a programmer to rely on abstractions.

Example
/*
 * Represents a set of integers, that is, a collection of integers
 * that doesn't contain any duplicates.
 */
class IntegerSet {
    /* ... */
};

Function/Method Comments

Function comments must include the following items:

  • The purpose of the function
  • The purpose of all parameters
  • What the function/method returns (and under what conditions)
  • Any preconditions that are necessary for the function/method to work correctly

The comment should explain exactly what the function does, without explaining how it does what it does. Users probably won't be able to see what the code inside the function does, so they must rely on the function comments to determine how to use the function. The reader cannot see your local variables, so you should not mention them. Likewise, they cannot see the private instance variables and functions, so you should not mention them either.

Avoid Prefer
/*
 * Sets up a temporary variable i,
 * and uses a for-loop from 0 to
 * size-1 to find something in the
 * list. 
 */
bool List::contains(int e) {
    /* ... */
}
/*
 * Returns true if this list
 * contains integer e, false
 * otherwise. 
 */
bool List::contains(int e) {
    /* ... */
}

Variable Comments

All instance variables and almost all other variables need a comment describing their purpose. It is also a good idea to document any relationships between variables and any restrictions on the range of values the variables can take.

Example
/*
 * Represents a set of integers, that is, a collection of integers
 * that doesn't contain any duplicates.
 */
class IntegerSet {
private:
    // The number of integers in this set.
    int numElements;

    // The integers in this set. They occupy the positions starting
    // at index 0 and ending at numElements-1.
    int elements[NUM_ELEMENTS];

    /* ... */
};

Internal Comments

Implementation details should be documented in internal comments.

In general, you should comment groups of related statements, like loops or key sequences in the code.

Examples
// Searches the linked list for e, starting with front. If
// found becomes true, then e has been found.
bool found = false;
ListNodePtr current = front;
while ((current != NULL) && !found) {
    if (current->data == e) {
        found = true;
    }
}
// Prompt the user for their name and create a new player.
Player* player;
char name[50];
cout << "What is your name?" << endl;
cin >> name;
player = new Player(name);

If you keep your functions short, then there won't be much need for internal comments. (On a somewhat related note, short functions are also easier to debug.)


Names

Naming conventions make programs more understandable by making them easier to read. They can also give information about the purpose of the identifier-for example, whether it's a constant, function, or class-which can be helpful in understanding the code.

Class/Struct Names

Class/struct names should be nouns, in mixed case with the first letter of the name and the first letter of each internal word capitalized.

Try to keep your class/struct names simple and descriptive. Use whole words--avoid acronyms and abbreviations (unless the abbreviation is much more widely used than the long form, such as URL or HTML).

Examples
class Set;
class IntegerSet; 

Function/Method Names

Function/method names should be verbs, in mixed case with the first letter lowercase and the first letter of each internal word capitalized.

Names for functions/methods which get and set an attribute of a class should be prefixed with get and set. Names for methods which test a boolean condition should be prefixed with is.

Examples
void run();
void runFast();
int getSpeed();
void setSpeed(int s);
bool isStoked();

Variable Names

Variable names should be in mixed case with the first letter lowercase and the first letter of each internal word capitalized.

Variable names should be short yet meaningful. The choice of a variable name should be mnemonic--that is, designed to indicate to the casual observer the intent of its use. One-character variable names should be avoided except for temporary throwaway variables, e.g. i, j, k, m, and n for integers.

Examples
int i;
char c; 
float interestRate;

Constant Names

Constant names should be all uppercase with the words separated by underscores ("_").

Examples
#define NORTH (0);
#define MIN_WIDTH (4);

General Formatting

Some general formatting guidelines are described here. More specific guidelines, as they pertain to classes, functions, etc. are described in the next section.

Indentation

Four spaces should be used as the unit of indentation. The exact construction of the indentation (spaces vs. tabs) doesn't really matter, but it should be consistent-do not mix spaces and tabs.

Blank Lines

Blank lines improve readability by setting off sections of code that are logically related.

One blank line should always be used in the following circumstances:

  • Between class/struct definitions
  • Between function/method definitions
  • Between the local variables in a function/method and the function/method's first statement
  • Before a comment
  • Between sequences of related statements inside a function/method

Line Length

Avoid lines that are longer than 80 characters. Such lines are difficult to read, especially when your code is printed out since they wrap and span multiple lines.

If your editor doesn't display the line width, you can always make a line of 80 characters and paste it in to check whether you've gone over. If you're reading this electronically, you can copy and paste the following line into your file (make sure to align it at the left margin):

/******************************************************************************/

Wrapping Lines

When an expression will not fit on a single line, break it according to these general principles:

  • Break after a comma.
  • Break before an operator.
  • Prefer higher-level breaks to lower-level breaks.
  • Align the new line with the beginning of the expression at the same level on the previous line.
  • If the above rules lead to confusing code or to code that's squished up against the right margin, just indent 8 spaces instead.
Examples
someMethod(longExpression1, longExpression2, longExpression3, 
        longExpression4, longExpression5);
var = someMethod1(longExpression1,
                someMethod2(longExpression2,
                        longExpression3));
longName1 = longName2 * (longName3 + longName4 - longName5)
            + 4 * longname6;

Formatting Statements, Declarations and Definitions

Compound Statements

Compound statements are statements that contain lists of statements enclosed in braces ("{" and "}"). When coding compound statements, the enclosed statements should be indented one more level. Examples can be found in the following sections.

Class/Struct Definitions

When coding classes/structs:

  • The opening brace ("{") should appear right after the class/struct identifier, separated by a space, or on the next line, under the start of the class/struct keyword.
  • The closing brace ("}") should start a line by itself, lined up with the start of the class/struct keyword.
  • The private:, protected: and public: access specifiers, if any, should also be lined up with the start of the class/struct keyword.
Example
/*
 * Represents a set of integers, that is, a collection of integers
 * that doesn't contain any duplicates.
 */
class IntegerSet {
private:
    // The number of integers in this set.
    int numElements;

    // The integers in this set. They occupy the positions starting
    // at index 0 and ending at numElements-1.
    int elements[NUM_ELEMENTS];

public:
    /*
     * Adds e to this set. 
     */
    void addElement(int e)
    
    /* ... */
};

Function/Method Declarations/Definitions/Calls

When coding function/method declarations/definitions/calls:

  • No space should appear between the function/method name and the opening parenthesis ("(") starting the argument/parameter list.
  • A blank space should appear after commas in the argument/parameter list.

Additionally, when coding function/method definitions:

  • The opening brace ("{") should appear right after the parameter list separated by a space, or on the next line under the start of the function/method header.
  • The closing brace ("}") should start a line by itself, lined up under the start of the function/method header.
Examples
IntegerSet union(const IntegerSet& s1, const IntegerSet s2);
IntegerSet s3 = union(s1, s2);
IntegerSet union(const IntegerSet& s1, const IntegerSet s2) {
    /* ... */
}

Control Statements

When coding control statements, such as those involving the keywords if, switch, for, or while:

  • A blank space should separate the keyword and the opening parenthesis ("("). This helps to distinguish the control statement from a function/method call.
  • Braces should be used around all statements, even single statements. This makes it easier to add statements without accidentally introducing bugs due to forgetting to add braces.

Additionally, when coding for statements:

  • A blank space should appear after the semi-colons separating the expressions.

Additionally, when coding switch statements:

  • The case constantExpression: and default: case specifiers, should be lined up with the start of the switch keyword.
  • Every time a case falls through (doesn't include a break statement), add a comment where the break statement would normally be (e.g. // falls through).
Examples
if (heroine.isDefiant()) {
    heroine.trashTalk();
    heroine.fight(villain);
}
else if (heroine.isLost()) {
    heroine.goWest();
}
while (true) {
    runInCircles();
}
for (i = 0; i < n; i++) {
    process(a[i]);
}
switch (ch) {
case 'h':
    sayHello();
    // falls through
case 'o':
    order(sandwich);
    break;
case 'g':
    sayGoodNight();
    break;
default:
    leave();
    break;
}

Programming Practices

Constants

Avoid coding constants directly (also known as using magic numbers). Use #define or const to define constants, and place them at the top of the file in which they are defined (just after the header comment).

Avoid Prefer
for (i = 0; i < 4; i++) {
    process(points[i]);
}
#define NUM_POINTS (4)
/* ... */
for (i = 0; i < NUM_POINTS; i++) { process(points[i]); }

Assignments

Avoid assigning several variables to the same value in a single statement. This is hard to read. Separate assignments.

Avoid Prefer
a = b = 1;
a = 1;
b = 1;

Parentheses

It is generally a good idea to use parentheses liberally in expressions involving mixed operators to avoid operator precedence problems. Even if the operator precedence seems clear to you, it might not be to others-you shouldn't assume that other programmers know precedence as well as you do.

Avoid Prefer
if (a == b && c == d)
if ((a == b) && (c == d))

Boolean Expressions

Avoid testing boolean expressions for equality with 1 (or true) or 0 (or false). It is much more concise to test boolean expressions directly. It also distinguishes such tests from those which check if two integers are equal.

Avoid Prefer
if (a == 1)
if (a)
if (a == true)
if (a)
if (a == 0)
if (!a)
if (a == false)
if (!a)
if (a && b == 0)
if (a && !b)

Returning Values

Try to make the structure of your program match the intent.

Avoid Prefer
if (booleanExpression) {
    return true;
} else {
    return false;
}
return booleanExpression;
if (condition) {
    return x;
}
return y;
return (condition) ? x : y;

Special Comments

Use XXX in a comment to flag something that is bogus but works. Use FIXME to flag something that is bogus and broken.


CSC181 Home Page | Last updated on 2000-12-01 by Ray Ortigas.

Adapted from Java Guidelines (in CSC148 Course Handbook, 6th ed.). Copyright 1999 Paul Gries, Department of Computer Science, University of Toronto.
Adapted with permission from Code Conventions for the Java(TM) Programming Language. Copyright 1995-1999 Sun Microsysytems, Inc. All rights reserved.