Theme index -- Keyboard shortcut: 'u'  Previous theme in this lecture -- Keyboard shortcut: 'p'  Next slide in this lecture -- Keyboard shortcut: 'n'Contracts and Assertions

A complete PDF version of the text book is now available. The PDF version is an almost complete subset of the HTML version (where only a few, long program listings have been removed). See here.

51.  Responsibilities and Contracts

This section is about responsibilities and contracts, and their connection to preconditions and postconditions. Recall from Section 2.2 in the initial lecture that we already touched on responsibilities in the slipstream of the pizza delivery example, see Figure 2.1. At the end of the chapter, in Section 51.8 we briefly discuss Design by Contract, which broadens the scope for applicability of contracts in the development process.

51.1 Division of Responsibilities51.5 Everyday Contracts
51.2 The highly responsible program51.6 Contracts: Obligations and Benefits
51.3 Responsibility division by pre and postconditions51.7 Obligations and Benefits in Sqrt
51.4 Contracts51.8 Design by Contract
 

51.1.  Division of Responsibilities
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index 

A class encapsulates some description of state, and some operations. A subset of the operations make up the interface between the class and other classes. All together, the class manages a certain amount of responsibility. Internally, the class is responsible for keeping the state consistent and sound. Externally, the operations of the class are responsible for delimitation of the messages that they handle, and the quality of the work (results) the operations deliver.

It is bad if a class is irresponsible. Class irresponsibility may occur if a pair classes both expect the other class to be responsible.

It is also bad if a class is too responsible. A pair of over-responsible classes redundantly care about the same properties. This is not necessary, and it bloats the amount of program lines in the implementation of the classes.

This leads us to the essence of this and the following sections, namely division of responsibilities. Let us first enumerate the consequences of well-defined and ill-defined division of responsibilities:

  • Without well-defined division of responsibilities

    • All classes accept a large responsibility

    • All program parts check all possible conditions (defensive programming)

    • Makes a large program even larger

  • With well-defined division of responsibilities

    • Operations can safely operate under given assumptions

    • It is well-defined which parts should check which conditions

    • Simplifies the program

 

51.2.  The highly responsible program
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index 

Before we proceed to the role of preconditions and postconditions in relation to responsibility, we will study an example of an object-oriented program with two classes that altogether are over-responsible.

We make our points with yet another version of class BankAccount, see Program 51.2, in relation to a client of class BankAccount, see Program 51.1. As you will realize below, the illustration of over-responsibility is slightly exaggerated in relation to a real-life program.

The Main method in Program 51.1 withdraws and deposits money on the bank account referred by the variable ba, which is declared and initialized in line 5. Before withdrawing money in line 8, Main checks the soundness of the account (with AccountOK), and it checks if there are enough money available. After the withdrawal Main checks if the account is still sound. It also deals with the situation where Main withdraws an amount of money, which is greater then the balance of the account. Similar observations apply to Deposit in line 19.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Client{

  public static void Main(){

    BankAccount ba = new BankAccount("Peter");

    if (ba.AccountOK && ba.EnoughMoney(1000))
      ba.WithDraw(1000);
    else
      WithdrawingProblems("...");
    if (!ba.AccountOK)
      MajorProblem("...");
    if (ba.Balance <= 0)
      BankAccountOverdrawn(ba);

    ...
  
    if (ba.AccountOK)
      ba.Deposit(1500);
    if (!ba.AccountOK)
      MajorProblem("...");

  }
}
Program 51.1    Excerpt of highly responsible class Client of BankAccount.

In class BankAccount below, the Withdraw method in line 9-16 check the soundness of the bank account, and it deals with insufficient funds, before the actual withdrawal takes place in line 15.

The Deposit method in line 18-24 cares about the situation where clients deposit very large amounts. In such cases the bank account attempts to check if the money comes from illegal or criminal sources.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class BankAccount {

   private double interestRate;
   private string owner;
   private double balance;

   // ...

   public void Withdraw (double amount) {
      if (!AccountOK)
        ComplainAboutNonValidAccount();
      else if (!this.EnoughMoney(amount))
        ComplainAboutMissingMoney();
      else
        balance -= amount;
   }

   public void Deposit (double amount) {
      if (amount >= 10000000)
        CheckIfMoneyHaveBeenStolen();
      else if (!AccountOK)
        ComplainAboutNonValidAccount();
      alse balance += amount;
   }
}
Program 51.2    Excerpt of highly responsible class BankAccount.

Seen altogether, the amount of code in Program 51.1 and Program 51.2 is much larger than desired. The checks that happen more than once should be eliminated. In addition, some of the responsibilities should be delegated to third party objects.

 

51.3.  Responsibility division by pre and postconditions
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index 

Preconditions and postconditions can be used to divide the responsibility between classes in an object-oriented program. The idea is to make it the responsibility of particular objects to fulfill the precondition of a method, and to make it the responsibility of other objects to fulfill the postcondition of a method. The rules are as follows:

  • Fulfillment of the precondition

    • The responsibility of the caller

    • The responsibility of the client in an object-oriented program

  • Fulfillment of the postcondition

    • The responsibility of the called operation

    • The responsibility of the server in an object-oriented program

Client and server are roles of objects relative to the message passing in between them. The client and server roles were discussed in Section 2.1. In some books, the server is called a supplier.

Let us recall the precondition and the postcondition of the square root function sqrt, as shown in Program 49.2. A function that calls sqrt is responsible to pass a non-negative number to the function. If a negative number is passed, the square root function should do nothing at all to deal with it. If, on the other hand, a non-negative number is passed to sqrt, it is the responsibility of sqrt to deliver a result which fulfills the postcondition. Thus, the caller of sqrt should do nothing at all to check or rectify the result.

Now we know who to blame if an assertion fails:

Blame the caller if a precondition of an operation fails

Blame the called operation if the postcondition of an operation fails

 

51.4.  Contracts
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index 

In everyday life, a contract is an enforceable agreement between two (or more) parties. Often, contracts are regulated by law. In relation to programming in general, we define a contract in the following way:

A contract expresses the mutual obligations in between parts of a program that cooperate about the solution of some problem

In object-oriented programming it is natural that the program parts are classes.

The preconditions and the postconditions of the public methods in a class together form a contract between the class and its clients.

It can be a serious matter if a contract is broken. A broken contract is tantamount to an inconsistency between the specification and the program, and it is usually interpreted as an error in the program. The error is usually fatal. A broken contract should raise and throw an exception. Unless the exception is handled, the broken contract will cause the program to stop.

 

51.5.  Everyday Contracts
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index 

Contracts are all around us in our everyday life

When we do serious business in our everyday life, we are very much aware of contracts. When we accept a new job or when we buy a house, the mutual agreement is formulated in a contract.

Below we list some additional everyday contracts:

  • Student and University

    • The student enrolls some course

    • The university offers a teacher, a room, supervision and other resources

  • Citizen and Tax office

    • The citizen does a tax return

    • The tax office calculates the taxes, and regulates the paid amount of money

  • Football player and Football club

    • The player promises to play 50 games per season

    • The football club pays 10.000.000 kroner to the player pr. month

  • Citizen and Insurance company

    • The insurance holder pays the insurance and promises to avoid insurance fraud

    • In case of a damage or accident, the insurance company pays compensation

 

51.6.  Contracts: Obligations and Benefits
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index 

Contracts in object-oriented programs, specified by preconditions and postconditions of certain methods, express obligations and benefits.

In Figure 51.1 we personalize the obligations and benefits of a client and server. In the context of Figure 51.1 the server is called a supplier. This terminology, as well as the syntax used in the illustration, come from the object-oriented programming language Eiffel [Meyer97, Meyer92, Switzer93].

Figure 51.1    A give-and-take situation involving a client and a server (supplier) class.

The Client, shown to the right in Figure 51.1 must make an effort to arrange, that everything is prepared for calling opSupplier in the class Supplier. These efforts can be enjoyed by the supplier, because he can take for granted that required precondition of opSupplier is fulfilled.

The roles are shifted with respect to the rest of the game. The supplier must make an effort to ensure that the postcondition of opSupplier is fulfilled when the operation terminates. This reflects the fact the operation has done the job, as agreed on in the contract. In return, the client can take for granted that the opposite party (the supplier) delivers an appropriate and correct result.

The obligations and benefits of the contract can be summarized as follows:

Obligation - May involve hard work

Benefit - A delight. No work involved

If you feel that the discussion in this section is too abstract, we will rephrase the essence in the next section relative to the squareroot function.

 

51.7.  Obligations and Benefits in Sqrt
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index 

In Program 49.2 of Section 49.3 we exemplified axiomatic specifications with a squareroot function. Let us, of convenience, rephrase the specification here.

1
2
3
4
5
sqrt(x: Real) -> Real

  precondition: x >= 0;

  postcondition: abs(result * result - x) <= 0.000001
Program 51.3    An axiomatic specification of the squareroot function.

The obligations and benefits of sqrt, relative to its callers, are summarized in the following table:

- Obligation Benefit
Client Must pass a non-negative number Receives the squareroot of the input
Server Returns a number r for which r * r = x Take for granted that x is non-negative
Table 51.1    A tabular presentation of the obligations and benefits of the squareroot function (in a server role) and its callers (in a client role).

Notice in particular the obligation of the client and the benefit of the server, as emphasized using the red color in the table.

 

51.8.  Design by Contract
Contents   Up Previous Next   Slide Annotated slide Aggregated slides    Subject index Program index Exercise index 

As presented in Section 51.4, a contract of a class is the sum of the assertions in the class. Thus, a contract is formed by concrete artifacts in the source program.

As part of the Eiffel efforts [Meyer97, Meyer92, Switzer93], the use and benefits of contracts have been broadened such that contracts affects both design, implementation, and testing. The broad application of contract is known as Design by Contract (DBC). Design by Contract is a trademark of the company Eiffel Software, and as such it may be problematic to use the term, at least in commercial contexts.

Design by ContractTM (DBC) represents the idea of designing and specifying programs by means of assertions

The following summarizes the use of contracts in the different phases of the software development process, and beyond.

  • Design: A pragmatic approach to program specification

  • Documentation: Adds very important information to interface documentation of the classes

  • Implementation: Guides and constrains the actual programming

  • Verification: The program can be checked against the specification every time it is executed

  • Test:

    • Preconditions limit the testing work

    • The check of postconditions and class invariants do part of the testing work

  • End use: Trigger exception handling if assertions are violated

The use of contracts for design purposes is central. The contract of a planned class serves as the specification of the class. We have discussed program specifications in Section 49.3 of this material.

Interface documentation - as pioneered by JavaDoc - includes signatures of methods and informal explanations found in so-called documentation comments. It is very useful to include both preconditions, postconditions, and class invariants in such documentation.

During program execution - both in the testing phase and in the end use phase - the actual state of the program execution can be compared with the assertions. As such, it is possible to verify the implementation against the specification at program run-time. If an inconsistency is discovered during testing, we have located an error. This is always a pleasure and a success. If an inconsistency is discovered during end use, an exception is thrown. This is clearly less successful. Exceptions have been treated in Chapter 33 - Chapter 36 of this material.

 

51.9.  References
[Switzer93]Robert Switzer, Eiffel and Introduction. Prentice Hall, 1993.
[Meyer92]Bertrand Meyer, Eiffel the Language. Prentice Hall, 1992.
[Meyer97]Bertrand Meyer, Object-oriented software construction, second edition. Prentice Hall, 1997.

Generated: Monday February 7, 2011, 12:22:40
Theme index -- Keyboard shortcut: 'u'  Previous theme in this lecture -- Keyboard shortcut: 'p'  Next slide in this lecture -- Keyboard shortcut: 'n'