Affine/Linear Code (Doing Something At Most/Exactly Once)

The Problem

Requiring a method to perform a certain kind of action at most once (or exactly once) is a need I encounter practically on a daily basis.

  1. A method giving its caller a set of information through a callback (or running a task specified by a callback) should not invoke the callback more than once.
  2. A set of related variables may be calculated differently depending on runtime circumstances, but they must not be assigned more than once.
  3. A web controller/rpc method may perform one read-write transactional service call, not more.
  4. An initialisation method must be called exactly once.
  5. A dependency of a component must be set (injected) precisely once.

I could go on. I will use the qualifiers affine and linear for these properties (at most once, exactly once, respectively), by analogy with the corresponding features of behavioural type systems.

The Level One Tools

How can we ensure that these requirements are met? As always, the way to achieve Level One or Two is to look for features of the compiler that enforce similar properties, and see if we can bend them to implement our actual needs.

These are the linear and affine properties I could think about, that are offered by the Java compiler:

  1. A constructor must invoke the super constructor exactly once (or at most once if the super class has a default constructor).

  2. A final field must be initialised exactly once.
  3. A final local variable must be initialiased at most once (if the variable is read, then it must be initialised exactly once).
  4. A method with a non-void return type must return a value exactly once.

Example: Final Variables

Not all of these can be applied to all problems, at least not in an elegant way. For instance the java compiler imposes the constraint that an invocation of the super-constructor must be the first statement (even though there is no such restriction at the bytecode level, see this discussion on stackoverflow.com), so running code prior to that invocation is made more difficult.

A set of related variables may be calculated differently depending on runtime circumstances, but they must not be assigned more than once.
If more than one variable must be set, final variables are the best solution:

/* What shall we have tonight? */
final Food food;
final Drink drink;
if (todayIsSaturday()) {
  food = FISH; // family tradition
  drink = WHITE_WINE;
} else {
  Food flatmateFood = whatIsFlatMateCooking();
  if (noAllergies(flatmateFood)) {
    food = flatmateFood;
  } else {
    food = SPAGHETTI; // when in doubt
  }
  if (food == MEAT) {
    drink = RED_WINE;
  } else {
    drink = APPLE_JUICE;
  }
}
eat(food);
drink(drink);

If there is any code path that doesn’t initialise one of food and drink you’ll get an error at the eat() or drink() invocations. If any code path attempts initialising one of them twice, it will complain that a final variable may not be reassigned.

If only one variable is to be used, the linearity of return statements may be exploited:

eat(chooseFood());
/* ... */
private Food chooseFood() {
  if (todayIsSaturday()) {
    return FISH; // family tradition
  } else {
    Food flatmateFood = whatIsFlatMateCooking();
    if (noAllergies(flatmateFood)) {
      return flatmateFood;
    } else {
      return SPAGHETTI; // when in doubt
    }
  }
}

Example: Return Statements

Don’t invoke the callback more than once.

Suppose a callback interface of this form:

interface Callback {
  public void myNameIs(String firstname, String lastname);
  public void iHaveNoName();
}

and a service interface of this form:

interface MightHaveAName {
  /** Calls one method of the callback exactly once. */
  public void whatsYourName(Callback callback);
}

How can we guarantee that all implementations of the second interface satisfy the contract? We can use linearity of return statements, by replacing the interface with an abstract class:

abstract class MightHaveAName {
  protected class MyNameIs {
    final String firstname;
    final String lastname;
    public MyNameIs(String firstname, String lastname) {
      this.firstname = firstname;
      this.lastname = lastname;
    }
  }

  /** Calls one method of the callback exactly once. */
  public final void whatsYourName(Callback callback) {
    final MyNameIs result = getName();
    if (result == null) {
      callback.iHaveNoName();
    } else {
      callback.myNameIs(result.firstname, result.lastname);
    }
  }

  protected abstract MaybeName getName();
}

Almost correctly used like this:

public class Someone extends MightHaveAName {
  private MaybeName helperMethod(...) {
    if (something) {
      return MyNameIs("Jack", "Jackson");
    } else {
       return null;
    }
  }
  protected MaybeName getName() {
    // some preparatory work here
    if (someComplicatedCondition) {
      // more work here
      return new MyNameIs("John", "Johnson");
    } else if (someOtherComplicatedCondition) {
      // still more work here
      return helperMethod(some, parameters);
    }
    // Oops! What if neither condition holds?
  }
}

… which will not compile, with an error saying getName() must return a result of type MaybeName.

As you can see, we can still delegate the work to helper methods, which can even be located in different classes, without ever risking multiple callback invocation. If the callback has more methods, the result type can be made into an abstract class or an interface with as many implementation as there are callback methods.

Example: Highlight Occurrences

Perform one read-write transactional service call, not more.

This could be achieved in similar ways to the previous examples but I thought I’d share a trick I used recently for this exact problem, to obtain Level Three. First declare a dummy exception with a private constructor:

public class WritingMethod extends Exception {
  private WritingMethod() {}
}

Then annotate all methods that write to the database with throws WritingMethod. This is what you then get when the cursor sits on the WritingMethod name:

Writing methods are highlighted

Even when a database-write is hidden in a helper method, it becomes visually obvious in the code.

Checked exceptions and the throws clause are the only behavioural property checked by the java type system, so they are often the only way to guarantee behavioural properties (writing to the database, having side effects, being non-deterministic, etc) of java code, in the sense that they propagate from a called method to a calling method, and may even be enforced at interface level (omitting the throws clause from a method forbids all implementors from having the associated behaviour).

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">