Short-Circuit Statements

What is a short-circuit statement? In this case, I’m not talking about the language feature related to boolean comparisons, but instead I’m talking about statements which cause a method to return as soon as some conclusion has definitely been reached. Here’s an example from a very simple compareTo method in Java:

public int compareTo(Foobar that) {
  if (that == null) return -1;
  if (this._value < that._value) return -1;
  if (this._value > that._value) return +1;
  return 0;
}

In this example, each line (except the last one) would qualify as a short circuit statement; that is, they all return as soon as a definite answer is determined, thus leaving some code in the method un-run.  If we weren’t using short circuit statements, then the code may look like this:

public int compareTo(Foobar that) {
  int result = 0;
  if (that == null) {
    if (this._value == that._value) {
      if (this._value < that._value) {
        result = -1;
      } else {
        result = +1;
      }
    }
  }
  return result;
}

For something this simple, there isn’t a huge difference in the complexity between the two functions, but it still demonstrates the point.  Many people ardently recommend always having a single return statement in any function, and would strongly advocate using the second example over the first.  However, I would argue that the first is superior because it better respects the unit economy of the reader.

Short circuit statements allow a reader to take certain facts for granted for the remainder of a method.  In the first example, after reading the first line of the method, the reader knows that they will never have to worry about the that variable having a null value for the rest of the method.  In the second example, the reader will have to carry the context of whether he is still reading code within the first if statement.  Every short circuit statement removes one item from the set of things one must consider while reading the remainder of the method.

Naturally, this example is pretty simplistic, and it’s a stretch to claim that either method is more complicated than the other.  However, consider if this weren’t a simple example. If this were a formula to compute an amortization table for a home mortgage, then the first few lines may look like this:

public AmortizationSchedule computeSchedule(
int principle, float rate, int term) {
  if (principle <= 0) throw new IllegalArgumentException(
      "Principle must be greater than zero");
  if (rate < 0.0) throw new IllegalArgumentException(
      "Rate cannot be less than zero");
  if (term <= 0) throw new IllegalArgumentException(
      "Term must be greater than zero");
  // Here is the 20 or so lines to compute the schedule...
}

In this case, there may be a substantial amount of code following this brief preamble, and none of it has to consider what may happen if these invariants are broken. This greatly simplifies the act of writing the code, the logic of the code itself, and the process of maintaining the code later on.

On the Naming of Methods

Methods are functions which are bound to a particular object.  The exact mechanism changes depending upon the language, but the general idea is that you don’t ever call them without knowing what object they belong to, and the that code inside them has access to the object.

Conceptually, this “binding” means that calling a method can more accurately be thought of as making a request of the object.  Imagine a class like this one:

class Dog(Animal):
    def __init__(self, name):
        self.name = name

    def speak(self):
        print("Woof!")

fido = Dog("Fido")
fido.speak()

In this example, you have Fido, a dog, whom you have asked to speak. Fido goes about that in a fashion typical of dogs. The method, speak, therefore should be phrased like a request or command so that we mentally hear the echo of the actual phrase we might use with a real dog: “Fido, speak!”

However, real methods often get much more complicated.  First, we often have a lot more of them, even on a single object.  Second, we often find that we have many similar methods where we want to be able to distinguish between them.  To that end, method names should take the form of short, imperative sentences with the (programming) object the method is bound to as the (grammatical) object of the sentence.  In practice, the desire to keep the sentences as simple as possible tends to lead to using this progression of sentence forms:

  • verb (render)
  • verbNoun (renderPlot)
  • verbAdverb (renderGradually)
  • verbAdjectiveNoun (renderTopAxis)
  • verbPrepositionNoun (renderWithBorder)
  • verbPrepositionAdjectiveNoun (renderWithGreenBorder)

So, when faced with picking a name for a given method, I try to start at the top of this list, and then work my way down until I can find a method name which meets these criteria:

  • unambiguous in the context of this object
  • re-uses common words and phrases already used in related code
  • fits the pattern of other methods in the object and related code
  • uses language common in the real-world domain the code is about

Roughly of half the time, the first form works just fine: as it did for our dog example.  If that name would be ambiguous within that class, then adding a single word will often do the trick.  So, for example, if I have a render method on a class already, and I want to refactor it into multiple parts, I might add methods named renderAxis and renderPlot into which I’ll refactor the pieces of the original method.

In all of this, I always use fully and correctly spelled words.  The shorter, simpler and more common the words the better. That way, I take advantage of the common agreement on spelling to help prevent errors from dissimilar misspellings / abbreviations.  The only exception, is when an abbreviation is more common than the long-form version (e.g., HTML is far more common than hyper-text markup language).

✧✧✧

The crucial thing I try to keep in mind when choosing method names is that I’m writing for the sake of other humans, and that methods should be tiny, imperative sentences directed at the object containing the method.  The next reader of the code may be a new developer learning the code for the first time, a colleague who needs to make a bug fix in this area, or even myself a few months down the road when the details aren’t so fresh.  Following a definite pattern aimed at both keeping things simple, and keeping this clear goes a long way towards making your code its own documentation.

Crow Epistemology

Our brain is an amazing organ, capable of truly astounding feats of abstraction and generalization, particularly when compared to a computer. On the other hand, it measures up pretty poorly when it comes down to managing a lot of information at once.  Ayn Rand, a 20th century philosopher, described this phenomenon as Crow Epistemology with the following story (paraphrased).

Imagine there are a bunch of crows sitting in the tree-tops at the edge of a forest. A pair of hunters pass them on their way into the forest, and all the crows get really quiet. One hunter comes out alone, but the crows stay quiet because they know there’s still another one in the forest. At little while later, the second hunter comes out, and as soon as he’s out of sight, the crows relax and start cawing again.

Now, imagine that a group of 20 hunters goes into the forest. The crows get all quiet, just like before. After a while, 15 hunters come out again. As soon as they’re out of sight, the crows start up with their cawing again. The crows could keep track of two hunters, but 20 was just too many for them to track by sight.

Of course, humans have the same problem. To address this, we create abstractions (like numbers) which allow us to group things together and keep track of them as a single unit. In our example, a boy sitting at the edge of the forest could simply count the hunters, and just remember one thing (the number 20). That way, he could easily know whether all the hunters had left the woods or not.

It turns out, programming is a lot harder than counting, and to do it, we need to keep all kinds of information stuffed in our heads. Naturally, the rules are no different, so we, as programmers, use lots of abstractions to keep everything straight. No one could possibly think about all the electrical signals racing around in a computer while they were designing a game. Even when designing a simple game, we need to break the program up into pieces, and complete each piece one at a time, and then stitch the parts together.

This process of using higher and higher abstractions to manage complexity is known as unit economy.  By grouping complex things together into a single unit, we can forget about how it works, and just remember what it does.  You don’t have to remember how a transistor works to understand what it does, just as you don’t need to remember how to implement a hash table to understand what it does.

The concept of unit economy is behind everything we do in our daily work as programmers.  Not too surprisingly, abusing a reader’s unit economy is the foremost way to make your code unreadable. I’ll have more to say on actually applying this principle in future posts.


For further reading:

  • Leroy, Charles Georges. “Letter VII. On the Instinct of Animals. The Intelligence and Perfectibility of Animals from a Philosophic Point of View: With a Few Letters on Man”. pgs 125-126. (Google Books)
  • Miller, George. “Magical Number Seven, Plus or Minus Two…”  (Wikipedia)
  • Rand, Ayn. “Introduction to Objectivist Epistemology” (Amazon)