20. Design by Contract™

Preconditions: before calling service, client must check everything is ready.

Invariants: something true both before and after the service is called

Postconditions: promises the service makes that should be met after the service finishes

e.g.

public class Stack<T> {
  /**
   * Precondition: stack not empty
   * Postcondition: stack unchanged, last pushed object returned
   */
  public <T> peek();

  /**
   * Precondition: stack not empty
   * Postcondition: stack size decreased by 1, last pushed object returned
   */
  public <T> pop();

  /**
   * Precondition: stack not full
   * Postcondition: stack sized increased by 1, `peek() == o`
   */
  public void push(T o);
}

The contract for a class is the union of the contracts of its methods.

Testing

Contracts inform testing; assertions allow us to check:

        Preconditions/
         Input Values
              |
              v
    |--------------------|
    | Software Component |
    |                    |
    | Errors/Exceptions  | --> Side Effects
    |                    |
    |--------------------|
              |
              v
       Postconditions/
        Output Values

Inheritance

Subclasses may have different pre/post conditions. Would require checking if the object is an instance of the subclass to determine if preconditions are met - this breaks the LSP.

Contracts are inherited:

That is, require no more, promise no less.

Hence, instead of saying that ‘Bar is-a Foo’, we can more formally say 'Bar conforms to the contract of Foo.

Guidelines

Specifying Contracts

Eiffel:

Informally, Java has assert expression: message; statements that are disabled by default (-ea flag required )

Philosophy for Exceptions

Java Exceptions iff a contract violation occurs.

Handling violations:

Hence, exceptions must be caught anywhere where clean up is needed.

Interfaces are contracts

Inheritance: The Dark Side