Saturday, 28 June 2014

Guideline #8. Define variables as close as possible to where they are used


Define variables as close as possible to their first use. Prefer variables with the most local scope as possible.

Complementary guidelines:

Do not reuse a variable for two totally different things inside the same function body, just to "save some space". It kills readability and it is very error prone.

Do not use exactly the same name for two variables with inner block scopes inside the same function body. It may hurt readability and it is error prone.



In previous guidelines we have been discussing the innermost pieces of software construction in C++: function bodies. All the guidelines we have seen make sense within that scope. Later we'll see guidelines which refer to the structures to which functions belong, that is, the classes. Even later we may consider how a number of classes are organized in a software project.

Guideline #7 instructed you to initialize all variables at the point of their definition, i.e., variables should begin to exist with a known value, to prevent undefined behaviour. The present guideline is a further recommendation about when should this (the variable definition and initialization) happen.

But what is a variable definition, anyway? Is it the same as a variable declaration?

Variable definition and declaration

This great answer on the software Q&A site Stack Overflow clarifies the meanings of variable declaration and definition in C++. Quoting:

A declaration introduces an identifier and describes its type, be it a type, object, or function. A declaration iswhat the compiler needs to accept references to that identifier. These are declarations:
extern int bar;
extern int g(int, int);
double f(int, double); // extern can be omitted for function declarations
class foo; // no extern allowed for class declarations

A definition actually instantiates/implements this identifier. It's what the linker needs in order to link references to those entities. These are definitions corresponding to the above declarations:
int bar;
int g(int lhs, int rhs) {return lhs*rhs;}
double f(int i, double d) {return i+d;}
class foo {};
A definition can be used in the place of a declaration. (...)

I strongly recommend that you read the complete answer.

In short we can say that inside a function body, at run time, a variable begins to exist once the code execution reaches the point where it is defined - not the point where it is only declared.

It benefits the readability of your code that you keep functions short and well structured. To achieve this, It is a key factor that every concept is limited to the exact scope where it belongs to. Define, initialize and use each variable exactly where it is needed, not any earlier. By following this simple guideline you will write code which is more readable, contains less defects, and is easier to debug.

Refactoring a function body is one of the most common tasks in software engineering. What was before in one function could be separated into several functions in the future. If you limit the scope of each variable to exactly the needed one, you will make this process much easier.

Complementary guidelines

If you have learnt the old C tradition of declaring all variables at the top of a funcion body, maybe it's time to consider abandoning it, in favour of a more compact and readable style.

If you have seen code in which a variable of a certain type is reused inside the function body for two or three different things, just to save some bytes, please forget about it. Use each variable exactly once - don't define variables which are never used, and don't use the same variable for several different things.

A local variable has only the scope of the braces which contain it. Because of this, a function may contain some inner block of code in which you define a variable, say, int i = 0;. Later in the same function you may have a later block of code in which you will be allowed to create another variable with the same type and name: int i = 0;. These are different variables, which totally disjoint scopes. This is perfectly correct. However, prefer not doing it. It is error prone and it hurts readability to have two different variables with the same name so close to each other. In fact, "i" is not a very expressive name - you should be able to come up with better names for both variables, names which say more about their meaning.



[McCONNELL 2004] This book discusses variable initialization in section 10.3: "Guidelines for initializing variables" (page 242). Scope is discussed in section 10.4: "Scope" (page 244). And the title of section 10.8 speaks for itself: "Using each variable for exactly one purpose" (page 255).

[MEYERS 1998-1] Scott Meyers advises us to "Postpone variable definitions as long as possible" in Item 32 of this book (page 135).

[SUTTER-ALEXANDRESCU 2004] The C++ Coding Standards suggested in this book include Item 18, "Declare variables as locally as possible" (page 35).

Web references