Representation invariants are constraints that all licit representation values must satisfy. We previously showed how to document them so that every person working on the code is aware of them. Yet mistakes may happen as the implementation can easily break the rep invariants, leading to inconsistent representation values and potential vicious bugs.

Fortunately, most rep invariants can easily be translated into code. It is thus possible to check them at runtime, thereby highlighting problems as soon as they occur and preventing consequent errors in your program.

Benefits of runtime checking

The first benefit of checking rep invariants at runtime is to catch bugs quickly. Indeed, you are informed as soon as something wrong occurs with your representation values. Not noticing violations would make the program run with illicit representation values until these later generate more critical, hardly recoverable problems. Moreover, the later you detect a bug the harder it is to identify its source and fix it.

A common mistake when one writes rep invariants is to make them too strong, i.e., imposing constraints that are unnecessary. By testing the rep invariant at runtime, one may detect that licit representation values are actually forbidden by the rep invariants.

In the end, it brings you a lot of confidence that your (complex) ADTs work as expected, even in production. Who wouldn’t sleep better at night knowing the application she’s in charge of is running without problem? 😉 And if something wrong should nonetheless happen, you’ll be able to trace down the problem quickly and provide a fix in no time.

These benefits are even more substantial when you program in more permissive languages such as C or C++. How often have you painfully tracked the origin of a segmentation fault that was ultimately due to a slight programming mistake in some inner ADT?

How-to: the checkRep method

For a given ADT, we typically implement the rep invariant in a method named checkRep. It takes no argument, has no effect, returns nothing, but throws an unchecked exception if the rep invariant is broken. Which exception type to raise is a matter of taste. In Java this could be IllegalStateException, AssertionError, or any other subtype of RuntimeException (even a custom one made for this specific purpose).

Whatever the exception type, it is essential to add a message explaining which invariant is broken. The end users of the application should not read this message; its purpose is to give information to developers who maintain the application. For example, knowing the line of code that raised the exception can be enough to track down the problem and fix it.

If you can’t implement part of the rep invariant as executable code (or feel you shouldn’t), this should be left as a comment.

We suggest placing the checkRep method right after the instance variables. One can write the rep invariants before the method, or interleave it with the code of the method. Which way you choose to go is a matter of taste. We personally prefer writing it before because we feel it’s clearer, especially when the rep invariant reach a certain complexity. On the contrary, interleaving the invariants with the code could make it more likely that both will remain in sync.

Implementing checkRep: the bank account example

In the following example, we implement the rep invariants of a bank account ADT. Our implementation throws an IllegalStateException when some invariant if broken.

private int balance;
private List<Transaction> transactions;

/*
 * Representation Invariant:
 *   balance >= 0
 *   transactions != null
 *   balance = sum (for all i) transactions[i].amount
 */

private void checkRep() {
    if (balance < 0) { throw new IllegalStateException("balance should be >= 0");
    }

    if (transactions == null) {
        throw new IllegalStateException("transactions should be not null");
    }

    int sum = 0;
    for (Transaction t : transactions) {
        sum += t.amount();
    }
    if (balance != sum) {
        throw new IllegalStateException(
                "balance should equal sum of transactions[i].amount");
    }
}

An alternative to IllegalState exceptions consists in using assertions, which may lead to clearer checkRep methods as they handle the test and the exception throwing. Yet we recommend not using the standard Java asserts (more on that later), but rather another like that of the Spring framework or your own.

// using Java assert, although I don't recommend it (more on that later)
assert balance >= 0 : "balance should be >= 0" ;
// using org.springframework.util.Assert (or you're own Assert class)
Assert.isTrue(balance >= 0, "balance should be >= 0");
// using AssertJ
assertThat(balance).isGreaterThanOrEqualTo(0);

Where to call checkRep

First, call checkRep at the end of every constructor. This confirms that the rep invariants hold each time an object is created. Then, do additional calls at the beginning and at the end of every public method, be it a mutator, a producer or an observer.

The reason to call checkRep at the end of mutators and producers is obvious: each modification and creation of rep values should preserve the rep invariants. As for observers, it may happen that an observer does not modify an abstract (visible) value but still changes the rep (internal) value, e.g. for optimization or modification purpose. This phenomenon is named benevolent side effect.

There remains the question of why one should call checkRep at the beginning of method calls. A common source of rep invariant violations is representation exposure: some method gives access to some instance variable that can later be modified by the client of the method. The direct modification of the instance variable may inadvertently break the representation invariant, as the client has no way to know (and check) them. Rep exposure should be avoided at all cost. If you’re confident that your implementation does not expose the rep, then you don’t have to call checkRep at the beginning of the execution.

The above recommendations and their benefits are summarized in the following structural induction:

If the representation invariants are:

  • established by creators;
  • preserved by producers, mutators, and observers;
  • and if the representation is never exposed;

then the invariants hold for all representation values.

We presented many good reasons to place many calls to checkRep without further thinking. However, from our experience and because we argue that rep invariants should be checked in production (more on that later), we only call checkRep at the end of every public constructor, producer and mutator.

This doesn’t apply to private methods, though; those may be called while the rep value is in an intermediate state that doesn’t satisfy the invariants.

 

Do you enforce invariants in your current project? How do you do it?