Function and Procedure Contracts


Contracts and documentation

A real piece of software, one that is not just a throw-away program, is a dynamic thing. People make modifications to programs to make them work better or to add new capabilities.

So it is important to make programs easy to modify. The most important thing to do to ease modification is to document your program. That means adding comments telling what different parts of the program accomplish.


What vs how

Each part of a program does some job. One thing that you want to document is what that job is. That is, what does the function accomplish?

A separate issue is how a part of a program accomplishes its job. For example, what does it use variables for? That is quite different from the issue of what the program or part of the program does.

For example, suppose that you get into a taxi. You tell the taxi driver what you want: take me to my destination. A separate issue, which you might or might not want to address, is how to get to your destination. If you are from out of town, you might not even know that. As long as the driver knows, you do not need to know.


Comments

You write documentation in programs as comments. In Cinnameg, a comment begins with %% and extends to the end of the line. If you need more than one line, start each one with %%. For example,

  %% This is a comment
  %% that is two lines long.
is how you write a comment in a program. The compiler ignores it.


Contracts

The basic documentation for a function or procedure is a contract. A contract tells what the function or procedure does, without telling how it works.

A contract must tell exactly what the function does and how each of its arguments affects what it does. It is not a vague hint. The idea is that you can understand what the function does, and know enough to use the function, just from the contract, without even looking at the definition of the function.

For example, suppose that quadratic(a,b,c) yields a solution to quadratic equation ax2 + bx + c = 0, assuming that a solution exists. A reasonable first stab at a contract is

  %% quadratic(a,b,c) returns a value x such that
  %% ax^2 + bx + c = 0.
Sometimes, functions and procedures have requirements that anyone using them should know. Those requirements must be included in the contract. For example, in addition to requiring there to be an answer, suppose that quadratic(a,b,c) requires a to be nonzero. The contract would be as follows.
  %% quadratic(a,b,c) returns a value x such that
  %% ax^2 + bx + c = 0.
  %%
  %% Requirements:
  %%   a is not 0.
  %%   There must exist a solution.

It can be difficult at first to write contracts. The problem is that you have spent a lot of effort working out how your function works, and you have become accustomed to thinking in terms of those details. But the contract should avoid them, and only tell what the function accomplishes, without saying how it works.

Contracts often contain examples. They can help to clarify just what a function or procedure does.

It can be tempting to talk about who uses a function or procedure, and where the arguments come from. But a contract should not do that. Suppose that you mention in a contract which other function uses this function. Now you modify the program so that you use this function in another place. You will need to modify the contract, since it is now incorrect. But the function did not change! It still does the same thing. Why should you need to modify its contract?


When to write contracts

A contract for a function or procedure is really a statement of the problem that the function or procedure solves. Here are two scenarios.

  1. [Scenario 1] First, decide what the function or procedure is supposed to do. Write it down (as a contract) so that just what you are trying to do is clear and right in front of you. Then write the definition to make the function or procedure do what it is supposed to do. Consult the contract whenever you have forgotten what you are shooting for.

  2. [Scenario 2] Start writing the function or procedure definition without quite knowing what it is supposed to do. Figure its job out as you go. Work on it until you have something that does something. Then try to figure out what it does, and write down your conclusion as a contract.

Which one sounds like a better idea? If you selected the first one, you are on track to become an excellent programmer. But to complete that, you need to put it into practice. It is tempting to believe that you can keep the contract in your head. But if you can, you should also be able to write it down. So do that, before you write the function or procedure definition.

Most beginning programmers choose scenario 2 in practice. Sometimes it is because they are uncomfortable writing anything in English. Sometimes it is because they have a poor understanding of what they are doing, and hope that, by flailing around, they will hit on something that works by accident. This is a big reason why many beginning programmers spend far longer working on their programs than they should really need. Experts never launch into writing a function or procedure definition without first getting a very good idea of what they want it to do.

Many beginners also have difficulty saying what a function or procedure does, and instead try to describe how it works. But if you write the contract before writing the definition, you cannot do that. There is no definition to look at when you are writing the contract!


Problems

  1. [solve] Write a clear and concise contract for the isSubstring function from a previous question.

  2. [solve] Write a clear and concise contract for the isSubstring function from a previous question. Is your contract for this definition different from your contract in the preceding problem?

  3. [solve] What is wrong with the following attempt at a contract. The function definition is given.

      %% sqr(x) yields the square of x.  It works by multiplying
      %% x by itself.
    
      Define
        sqr(x) = x*x
      %Define
    

  4. [solve] What is wrong with the following attempt at a contract. The function definition is given.

      %% isOdd(x) takes a number x that was typed by the user and
      %% yields true if x is odd, false if x is even.
      %% x by itself.
    
      Define
        odd(x) = x `mod` 2 == 1
      %Define
    

  5. [solve] What is wrong with the following attempt at a contract.

      %% solve(a,b,c) returns a solution to the equation.
    


Summary

Documentation is critical to making a program modifiable.

A contract for a function or procedure tells precisely what the function or procedure accomplishes, and how its parameters affect what it accomplishes, without saying how it works, who uses it or where it gets its arguments from. A contract can contain examples and must mention any requirements that the arguments must meet.


Review

Programs normally interact with a user. For simple text-based programs, that means reading information typed on the keyboard and writing information onto the console. But that does not mean that every function or procedure interacts directly with the user. In fact, most functions and procedures in a piece of software typically do not interact with the user in any way.