Disempower Every Variable


In which I argue you should reduce the circle of influence, and the ability to change, of every variable.

The more a variable can do, the harder it is to reason about. If you want to change a single line of code involving the variable, you need to understand all its other uses. To make your code more readable and maintainable, you should disempower all your variables as much as possible.

Here are two things you can do to minimize the power of a variable:

1: Reduce its circle of influence (minimize the scope)
I once had to make a bugfix in a 400 line function, containing tens of for-loops. They all reused a single counter variable:

{
  int i;
  (...)
  for (i = 0; i < n; ++i) {
  }
  (...)
  for (i = 0; i < n; ++i) {
  }
  //350 lines later...
  for (i = 0; i < n; ++i) {
  }
}

When looking at a single for-loop, how am I to know that the value of i is not used after the specific loop I was working on? Someone might be doing something like

for (i = 0; i < n; ++i) {
}
some_array[i] = 23

or

for (i = 0; i < n; ++i) {
}
for (; i < m; ++i) {
}

The solution here is of course to use a local variable to each for-loop (unless of course it actually is used outside of the loop):

for (int i = 0; i < n; ++i) {
}
for (int i = 0; i < n; ++i) {
}

Now I can be sure that if I change i in one for-loop, it won’t affect the rest of the function.

2: Take away its ability to change (make it const)

(I have blogged about const a few times before. It is almost always a good idea to make everything that doesn’t need to change const.)

Making a local variable const helps the reader to reason about the variable, since he will instantly know that its value will never change:

void foo() {
  const string key = getCurrentKey();
  (...) //Later...
  doSomethingWith(key);
  (...) //Even later...
  collection.getItem(key).process();

Here the reader knows that we are always working with the same key throughout foo().

In summary: Reduce the circle of influence (by reducing the scope) and take away the ability to change (by using const).

If you enjoyed this post, you can subscribe to my blog, or follow me on Twitter.

Minimize the Scope of Each Variable


Whenever you declare a variable, please make sure to make its scope as small as possible. Yesterday I was refactoring a pretty large function, with lots of loops in it. It looked something like this:

void f() {
  int index;
  double delta;
  //(...)tens of more variable definitions
  for (index = 0; index < _v1.size(); ++index) {
    delta = getDelta();
    //Computations, using delta and other variables
  }
  for (index = 0; index < _v2.size(); ++ index) {
    delta = getDelta();
    //Computations, using delta and other variables
  }
  //(...) hundreds of similar lines
}

This is of course a simplified example, the real function was four hundred lines long, and full of array-indexing and computations. (It had been ported more or less verbatim from Fortran, which explains the clustering of declarations at the top.)

The problem when making a change to such a function, is that the scope you need to understand is unnecessarily large. You never know if the value of index or delta is used in some clever way further down in the function, so if are changing it in one place, you basically have to grok the entire function.

On a side note, this is also a bad idea:

void f() {
  double delta;
  for (...) {
    delta = getVal();
    //Computations, using delta and other variables
  }

Even though it looks like you have cleverly optimized the definition of delta outside of the for loop, the only thing you have done is increase its scope and decrease readability. The compiler is perfectly capable of doing such optimizations for you.