next up previous
Next: Documentation Up: C++ Programming Style Previous: Structure/Modularity

Indentation and Braces

If functions are the paragraphs of the program, the statements are the sentences of the program, and they need to be properly punctuated. In fact, the task is even more demanding than mere puntuation (semi-colons after each statement, for example), because of the way that people read programs. The reader skips from place to place, jumping up to find variable declarations, jumping forward from a loop to the statement following it, and so forth. To make this easy, we must make the syntactic structure of the program visually evident. The compiler can count braces and semi-colons, but the reader's eye is best guided by indentation. In short:

Rule 5   Indentation is important. Code must be properly indented to show the syntactic structure of the program.

The syntactic structure of a program is a tree: statements have parts, and those parts can be statements in their own right, just as English sentences can contain multiple embedded clauses. Here's an example from psycholinguistics:

The rat the cat the dog chased bit died.
Sounds like gibberish, doesn't it? Even adding the restrictive relative pronoun doesn't help much:
The rat that the cat that the dog chased bit died.
What if I introduce some indentation:

The rat that
		the cat that
		 		the dog chased
		 		bit
		died.
It's still hard to understand, but we can see from the indentation that ``died'' belongs with ``the rat'' and it was the cat that bit the rat, and the dog that chased the cat.

Fortunately, English is rarely so heavily embedded as that toy sentence. Unfortunately, programs often are. We think nothing of code like the following:

for( int i=0; i<n-1; i++ ) {
   small=i;
   for( int j=i; j<n; j++ ) {
      if( A[j]<A[small] )      // line 1
         small=j;              // line 2
   }
   int temp=A[i];              // line 3
   A[i]=A[small];
   A[small]=temp;
}
The indentation is crucial to showing that line 2 is part of the statement starting on line 1. Similarly, the indentation is crucial to showing that line 3 comes after line 1 and is at the same level--both are contained in the outer for loop.

Would you rather read the following code?

for( int i=0; i<n-1; i++ ) {
small=i;
for( int j=i; j<n; j++ ) {
if( A[j]<A[small] )
small=j;
}
int temp=A[i];
A[i]=A[small];
A[small]=temp;
}
The thought is too horrible to contemplate.

Rule 6   A statement that belongs to (is part of) another statement should be indented relative to the containing statement. Statements that are at the same level in the syntax tree should be indented the same amount.

Most students know that they should indent, but they forget or they find it time-consuming. Here are a few hints:

Either of these indentation schemes will result in two other important properties of good indentation: it's visible (indenting only 1-2 characters is hard to notice; 3-4 is better) and it's consistent (if you sometimes indent 4 spaces and sometimes 8, I can't tell what level some statement is at.

Indentation is defined by syntactic structure, and syntactic structure is essentially defined by braces,For reasons I don't understand, many people call these characters {} ``curly braces'' and these ``square brackets.'' Since those are the only kind of braces I know, I just call them braces, and similarly I call the other things brackets. There is no reason I can think of for the extra adjectives. because braces enclose a sequence of statements where normally only one can occur. Thus, we are led to a discussion of brace placement, over which blood can easily be shed.

The standard method is as follows:

for( int i=0; i<n; i++ )
{
  A[i]=0;
}
Emacs does this automatically using the tab key, so this way is easy to follow.

Others like to do the following, presumably because the brace is contained in the for statement, as well as containing the assignment statement.

for( int i=0; i<n; i++ )
  {
    A[i]=0;
  }
You can do whichever you like, as long as you're consistent.

Another way of doing the braces is to begin at the end of the previous line:

for( int i=0; i<n; i++ ) {
  A[i]=0;
}
This produces a more compact style of code, which I happen to favor, as you've seen in previous examples. However, warning, I am in the minority on this. Most C and C++ programmers put braces on lines by themselves, and you should probably adopt that style. When in Rome, do as the Romans.

Another issue is whether to enclose single statements in braces. For example, the code above could have been written as follows:

for( int i=0; i<n; i++ ) 
  A[i]=0;
This eliminates the brace issue completely, and produces nice, compact code. The drawback, however, is a serious one. Suppose you decide that, just before the assignment statement, you'd like to print out the array element. So, you go add a statement:
for( int i=0; i<n; i++ ) 
  cout << A[i];
  A[i]=0;
Now you're in big trouble, because the assignment statement is no longer in the loop! In fact, you will be lucky in this case, because the compiler will probably complain that:
foo.cc:8: warning: name lookup of `i' changed for new ANSI `for' scoping
foo.cc:6: warning:   using obsolete binding at `i'
After thinking about that for a long while, you'll realize that, since the assignment statement is outside the loop, the i variable no longer exists.

You could also be saved if you have Emacs re-indent your code; you'd notice that the indentation became:

for( int i=0; i<n; i++ ) 
  cout << A[i];
A[i]=0;
and all would be clear.

However, many programmers prefer to avoid any risk of that occurring, and so they always use braces, whether for single statements or multiple statements. Either is acceptable.

Finally, there are annoying details, such as whether keywords can start after braces and such. That comes up with the little-used do...while construct. Choose one of the following, depending on what you like, and use it consistently:



do {
  cin >> response;
}
while ( response != 'N' );





do {
  cin >> response;
} while ( response != 'N' );



Personally, I prefer the one on the left, with the while keyword starting at the correct indentation level (and being colored correctly by Emacs), but either is acceptable.

While there is lattitude in using braces, some things are simply not done. For example, an open brace is always the last thing on a line. No one would do the following:

for( int i=0; i<n; i++ )
  { A[i] = 0;
    B[i] = 1; }
That goes double for statements on a single line. I might do the following if I was putting in debugging code, but that's only because I would delete such code before anyone else saw it:
for( int i=0; i<n; i++ ) { cout << A[i]; A[i] = 0; }
However, that doesn't mean that proper code is always starting a new line. Compact code is nice, and so single-statement blocks can be put on the same line as their containing statement:
for( int i=0; i<n; i++ ) A[i] = 0;
Contrast this with another acceptable style, which takes four lines instead of one:
for( int i=0; i<n; i++ ) 
{
   A[i] = 0;
}
We've already discussed the advantages of the latter, sparse style of coding, namely that it's easy to insert additional lines of code.

When functions, loops, and if statements get long, as can easily happen, it can become hard to visually match up the closing brace with the opening brace and, more importantly, the containing statement. If that is likely to happen, it is thoughtful to help the reader out, by saying what the brace is closing.


while (true)

...
Many lines of code
...
// end of while loop
We would probably not do this if the loop were short, say only 5-6 lines of code, because it clutters up the code and makes it harder to read. On the other hand, if the code in the loop is very long, we would probably try to introduce functions to make it more clear and compact. If that's not possible, then this marker is very important, despite the risk of visual clutter. After all, our goal in every case is to make the structure of the program easy to see.


next up previous
Next: Documentation Up: C++ Programming Style Previous: Structure/Modularity
James Hale
2001-09-19