THE WHAT AND WHEREFORE OF STYLE GUIDES
 

Perhaps the idea of programming style is best introduced by means of an example. First consider the program below. Even without the comment describing what it does, and the further comments explaining the algorithm used, it would not be too hard to work these things out. The code is well laid out, making it clear where loops begin and end (for example), the names of the variables are descriptive of what they're used for, and so on.
 

// This program reads in values and outputs whether or not
// they are prime numbers.
// Input ends when negative one is entered.
 

#include <iostream.h>
#include <conio.h>

void main (void) {

  int number, divisor,
  bool still_looking;

  cout << "Please enter a number (-1 to terminate): ";
  cin >> number;

  while (number > 0 ) { // stop on -1 or junk input

    // we have a valid number. to determine whether we've a
    // prime number, try all possible divisors starting with 2.
    divisor = 2;

    do {

      if ((divisor * divisor) > number) {

        // our divisor has reached the square root of the number.
        // the number must be prime.

        cout << number << " is a prime number" << endl;
        still_looking = false; // time to stop loopin

      } else if ((number % divisor) == 0) {

        // we've found something that divides the number.
        // the number is not prime.
        cout << number << " is a not prime number"
             << " (divisible by " << divisor << ")" << endl;
        still_looking = false; // time to stop looping

      } else {

        // nothing definite yet - must try the next divisor
        divisor = divisor + 1;
        still_looking = true;

      }

    } while (still_looking);

    // obtain the next number to be processed

    cout << "Please enter a number (-1 to terminate): ";
    cin >> number;

  }

}

Now consider the program below. As might be guessed by looking a some of the messages, it does the same thing as the program above. Indeed, from the compiler's point of view, the two are entirely equivalent. From the human point of view, however, there is obviously an enornmous difference. Instead of being understandable, the second program is a complete dog's breakfast. It's not obvious, for example, what the variables are used for and where the control structures (if's and loop's begin and end). Anybody who was just given this program would likely have extreme difficulty in making any sense of it.
 

#include <iostream.h>

#include <conio.h>

void main (void) { int n, x, bool l;
cout << "Please enter a number (-1 to terminate): ";
cin >> n;
while (n > 0) {
x = 2;
do { if ((x * x) > n) { cout << n << " is a prime number" << endl; l = false; } else
if ((n % x) == 0) {cout << n << " is a not prime number"
<< " (divisible by " << x << ")" << endl; l = false;
} else { x = x + 1; l = true; } } while (l);
cout << "Please enter a number (-1 to terminate): ";
cin >> number;
}}
 

The first of the programs represents good style, while the second represents bad (in fact awful) style. Style is important for a number of reasons. In the real world, the life cycle of a program extends far beyond getting it to run once. As requirements change over time (as they always seem to) programs must be modified to suit, and when bugs are discovered (again, as they inevitably are) they must be located and corrected. All of which is much more easily accomplished given "good" instead of "bad" code, especially when the person making the changes insn't the person who wrote the program in the first place. Code that can be understood by others is also essential when, as is normally the case, a program is too large to be written by a single individual, and must instead be a team effort.
 

Getting students to embrace style on the basis of what is necessary in industry has always been a bit of a hard sell. Students programs are normally short, written by a single individual, and "thrown away" once they work. There are, however, at least three very good reasons why students should embrace good programming style.

1/. It will prepare you for the real world.
2/. Far from being a nuisance, it in fact makes it easier to program.
3/. We insist on it, and we are where your marks come from.

Good style makes it easier to program because programs are less likely to contain bugs in the first place, and any bugs that might exist are more easily located. As a very simple example, imagine that we were to miss a squiggly bracket in typing in each of the sample programs presented above. In both cases the compiler would report the error, and we would be faced with working out where to make the necessary correction. This would be easy in the case of the good program, but quite a challenge in the case of the bad one. And it goes far beyond this. Nice indenting does just make a program look better, but also exposes the logical structure, making it much easier to determine whether something is amiss. And so on and so on.

A "Style Guide" is a set of rules intended to promote good programming style. The idea is not unique to ECOR 1606 or indeed to university programming courses. Style guides also exist in the real world, where they have the additional advantage of imposing a degree uniformity throughout a company's programs (so making it much easier for one programmer to modify a program written by somebody else).

Style guides are not a panacea. It is perfectly possible to produce programs which conform to the letter of a guide but which are nontheless hopelessly convoluted (as many students will doubtless prove). It can safely be said, however, that conforming to the 1606 style guide will very much increase your chances of producing good programs.
 

THE ECOR 1606 STYLE GUIDE
 

1. Indent Your Code

There is a lot of room for disagreement upon the finer details of "bad" and "good" style. Some people, for example, think that the "break" statement represents poor practice while others argue that it makes for better programs. Nobody, however, disputes that proper indenting is the very foundation of good programming style. Proper indenting never hurts, and it makes programs immeasurably easier to understand.

There are a number of indenting styles. Each has it advantages, it drawbacks, its advocates, and its detractors. While we insist that you consistently make use of one of these styles, you may use whichever one of them suits you best.

Style I (all sqiggly brackets on lines by themselves)

if (<condition>)
{
  <statements>
}
else
{
  <statements>
}

while (<condition>)
{
  <statements>
}

do
{
  <statements>
}
while (<condition>);

Style II (all closing squiggly brackets on lines by themselves)

if (<condition>) {
  <statements>
}
else {
  <statements>
}

while (<condition>) {
  <statements>
}

do {
  <statements>
}
while (<condition>);

Style III (Compact)

if (<condition>) {
  <statements>
} else {
  <statements>
}

while (<condition>) {
  <statements>
}

do {
  <statements>
} while (<condition>);
 

Whatever style you choose,  the elements of each construct must be aligned as shown.  In the case of Style I, for example, the "if", "{", "}", "else", "{", and "}" that go into an "if..then..else" must all line up.   The statements within constructs must be indented (again, as shown).   Indenting by just one space is inadequate, but beyond this the choice is left to the student.  There is somewhat of a tradeoff here.   Indenting by a relatively large amount (say 5 spaces) works well in the case of simple programs, but tends to push things too far to the right in the case of more complex programs.  Breaking statements over two lines and/or having statements that are too long for the screen does nothing at all for program legibility.   Indenting by just 2 spaces, while perhaps inferior in exposing the structure of a program, does come into its own when code gets complex and multiple indents are required.   Whatever size of indent is chosen should be used uniformly.  If you choose to indent by 3 spaces, for example, you should indent by 3 spaces everywhere.

The "short" forms of the if and so on are not permitted - you must use a (properly positioned) pair of squiggly brackets even when only a single statement is required. Admittedly some experienced programmers cheat a bit on this one, but there is a world of difference between experienced programmers and 1606 students, and using the "short" forms can land one in a lot of trouble.

Some programmers recommend adding a comment indicating just what is ending to the final '}' of each construct (as shown below). Others, however, argue that this gives a false sense of security because no error will be reported if one gets things wrong (and, for example, puts "end if" at the end of a while).

if (<condition>) {
  <statements>
} else {
  <statements>
} // end if

It can probably be said that this technique is most useful in the case of large programs in which an if or while may extend over several pages of code. Its use in 1606 is optional.
 

2. Don't Use Goto's

Given that we don't teach the C++ "goto" statement, this prohibition might seem a little academic. There always seem to be a few students, however, who somewhow discover that a "goto" is in fact part of C++.

In the hands of an expert programmer, goto's can, from time to time, actually improve a program. In particular they can be usefully employed to get around the unforunate fact that C++ does not otherwise support breaking out of nested loops. In general, however, goto's tend to lead to muddling thinking and to bad programs (generally known as "spaghetti code"). The goto is thus prohibited.
 

3. Don't Use Global Variables

Global variables, properly documented, can be a useful programming tool. They are, however, really only necessary in the case of programs much larger than anything we'll see in 1606 and, were they allowed, experience suggests that students would use them mostly as a way of avoiding of having to really understand how functions work. For this reason, global variables are prohibited.

Note that this prohibition does not apply to global constants, which are fine.
 

4. Use Meaningful Variable Names

There are cases in which terse, single character variable names are in fact appropriate. Consider, for example, the following code segement, which prints out a message ten times.

for (i = 0; i < 10; i++) {
  cout << "Hello world!" << endl;
}

In this case absolutely nothing would be gained by replacing "i" with a more "meaningful" name. Indeed using a longer name would probably make the code segment harder rather than easier to understand. Other examples could be offered. If the function of a piece of code is to determine the value of "x", "x" may be a quite reasonable variable name, and "n" is commonly used to represent the size of an array.

In general, however, variable names should be descriptive. Thus "speed" is much better than "s", and "population" is superior to "p". It is often a good idea to use multiple words (separated by underscrores) in naming variables. Thus, for example, one might have "initial_population", or "size_of_room".

The test of a good variable name is whether or not it conveys the role of the variable to the reader. While sometimes single character names will pass this test, this can be expected to be the exception rather than the rule. If all (or most) of your variables have single character names, you can be pretty sure that your program will not be acceptable.
 

5. Avoid Magic Numbers

A "magic number" is a constant which leaves the reader wondering just what is represents, and where on earth it came from. Consider, for example, the following statement:

angular_position = 57.29578 * (omega / i);

While some might recognize the value, it is far from clear just what is going on here, and in particular what the value represents. The value 57.29578 is a "majic value". Magic values are not good style and should be avoided by using named constants as shown below.

const double degrees_per_radian = 57.29578;

....

angular_position = degrees_per_radian * (omega / i);

Not only is the assignment statement now much more self-explanatory, but, if the constant were used in a number of places, there would much less chance of a typing error leading to the use of an incorrect value.

While all magic numbers are constants, not all constants are magic numbers. In the case below, the zero is just that . The reader knows what it represents, and does not wonder where it came from. Replacing the "0" with a named constant called "zero" would contribute nothing to the clarity of the program, and would instead just make it wordy.

if (speed < 0) { // speed is negative
  cout << "We're going backwards." << endl;
}
 

6. Put All Declarations First

In C++ it is permissable to intermingle "declarative" statements (the declaration of variables and constants) with what might be called "executable" statements (cin's, cout's, assignments, and so on). Indeed this approach was extensively employed in a previous text (and is one of the reasons we dropped it).

We strongly recommend, however, that students not mix things up, and instead declare first and execute afterwards If all declarations are kept together you'll always know where to look for them, and, more importantly, you'll avoid playing with fire. Declaring variables "on the fly" raises a number of issues which can get a bit tricky and which we won't be covering in this course. Consider, for example, the following code segment:

int b;

...

if (b < 0) {
  int a = 7;
} else {
  int a = 9;
}
cout << a << endl;

If you can understand why it will result in an error message to the effect that "a" is undefined, you are well ahead of the game and are not the kind of student we're worried about. If this makes no sense, on the other hand, you're well advised to avoid getting in over your head. Just put all your declarations first and this kind of thing won't crop up.

One somewhat special case is that of declaring a variable within a "for" loop as shown below.

for (int i = 0; i < 10; i++) {
  <statements>
}

While some would argue that this represents much better style than declaring "i" at the beginning of the function, it also has the potential to leave beginners very confused. If one breaks out of the loop, for example, "i" cannot be examined to determine when the break occurred. This is because, if declared in this fashion, "i" only exists for a long as the loop is being executing. Again, if this all sounds a bit scary, just don't take advatanges of this language feature. Declare "i" at the beginning, write the loop as "for (i = 0; ...", and everything should work as you expect it to.