Naming conventions

Introduction

In this section, we'll indicate some popular naming conventions that should be avoided, and we'll offer some guidelines for names that ease maintenance headaches.

Hungarian Naming Conventions (a bad idea)

Hungarian naming conventions prefix variable names by a code that gives an indication of its type. For instance, all integers are prefixed by the letter i, all pointers by p, etc.

The Hungarian naming convention---for which Hungarians should not be held accountable---represents an unfortunate attempt to set some conventions for coding. What is really obtained by such naming conventions is total breakdown of abstraction barriers. One of the fundamental principles of software engineering is to hide from a client all information that does not concern that client. Prefixing a variable by its type exposes exactly these unimportant implementation details to client code. Now, if the type of the implementation of a data type changes, all of the names of instances of that type must be altered as well.

Fields by the Structure Name (a bad idea)

Prefixing fields of a structure by some abbreviated part of the name of the structure is not only unnecessary, but directly duplicates the name information in all the fields. A change of the name implies changing all the field names as well, in addition to all references to a field name. Surely this is a maintenance nightmare that we don't want to perpetuate.

One might wonder, then, why this practice is so common. The reason is that early versions of the Unix C compiler had a particularly stupid way of managing its symbol table, requiring all field names of all structures to be unique. The only solution to the programmer was to use some kind of prefixing convention to avoid clashes. Modern compilers (and indeed it is required by the ANSI/ISO standard) have a separate namespace for each structure so that field names now have to be unique only within the same structure. There is therefore no need (and there hasn't been any need for a long time) to prefix field names by the structure name.

Module Prefix

A useful naming convention for the parts of a module that are exported and thus globally visible (usually the interface functions), is to prefix the names of a module with the name of the module, or some recognizable part of its name. For instance, a module that implements a data type ``set,'' could have its interface functions prefixed with set_. This is an easy way to avoid conflicts between modules---conflicts about common names such as insert, delete, etc.

Notice that suffixing is less useful than prefixing, since some linkers limit the number of significant characters that they can handle. With such linkers, the names may very well be truncated after six characters or so, causing two names such as insert_set and insert_queue to clash.

For the same reason (limited number of significant characters in the linker) module prefixes must be fairly short, or else not enough characters will be left for the names of the interface routines themselves. For instance, two names such as tree_delete and tree_destroy might become indistinguishable. The solution is to invent a shorter prefix of (say) three characters at most. Problems like this might disappear entirely in the future. The reason for the existence of such problems today, is that we still use linker technology from the 1960s. There is no reason (other than backward compatibility) for modern linkers to have such limitations.

For names that are locally known to a module, there is no need to use a prefix. Indeed, it could be useful for different modules to use the same name for internal functions with a similar purpose. For instance, the name init, may be used inside a module to initialize it.

Traditional Naming

Naming conventions should take traditions into account. For instance, the main() function of a C program takes two arguments describing the number of command line arguments and a table of these arguments respectively. These arguments are traditionally called argc and argv. Not only is it not useful to use different names, it is highly desirable that exactly these names be used so that programmers recognize them immediately.

Similarly, the variable name i and j are always loop counters. Never use these variable for other purposes, and always use these variables first for loop counters.

It is important never to mislead the maintainer by using incorrect names. An example of bad practice is the use of the identifier fd (usually a general-purpose file descriptor) for an object of type FILE *. Now, a file descriptor is defined in Unix to be an integer that is returned by the operation open(), and used as an argument to operations such as read() and write(). Distinct from it, there is also the concept of a file pointer FILE *. This is the type return by fopen() and used in operations such as fprintf(), etc. But a file pointer is not a file descriptor. Therefore, using fd as a variable of type FILE * is highly misleading to the maintainer.

Short Names and Long Names

Usually long names are more descriptive than short ones, but names can be descriptive for different reasons than the number of characters. For instance, the variables named i and j are nearly always used as loop counters. Calling these variables loop_count_one and loop_count_two or something similar is definitely not a way of making the program more readable.

Similarly, it is sometimes reasonable to call variables x or y. For instance, as arguments to a graphics routine that uses them to determine the position on the screen for some kind of object, these humble variables are well named. Similarly, for a function that implements arbitrary precision multiplication of two numbers, there is no reason to call the arguments multiplicand and multiplier. Simply use x and y!

Short names can also be used where the visibility of the variable is very limited. For instance, in order to traverse a list using a temporary pointer variable, we might use the name p for this variable as in the following example:

  {
    list p;
    for(p = first; p; p = p -> next)
      {
        /* only a few lines */
      }
  }
Using a longer name may cause the line
  for(p = first; p; p = p -> next)
to require more than 70 or so characters, making it hard to read. We may then have to split it into several lines, which increases the code size, i.e., the source, and creates a less common way of indenting the for loop.