CSC/ECE 517 Fall 2007/wiki3 2 at: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
 
(56 intermediate revisions by the same user not shown)
Line 1: Line 1:
<b>Topic:</b> <br>
In class, we had some difficulty coming up with good examples of programming by contract. Find some concise ones that illustrate the principle well, and are accessible to a general audience of programmers. <br>
Please note that as per the assignment requirement, we need to find good examples of programming by contract. So all the material and examples in this wiki has been taken from outside sources.
==Programming by contract==
==Programming by contract==
Programming by Contract is a way of specifying the behavior of a function, and the name arises from its formal similarity to a legal contract. The key concept is viewing the relationship between a class and its clients as a formal agreement, expressing each party’s rights and obligations. Defining a precondition and a postcondition for a routine is a way to define a contract that binds the routine and its callers. The precondition states the properties that must hold whenever the routine is called; the postcondition states the properties that the routine guarantees when it returns.
<br>
By associating clauses <b>require pre </b> and <b>ensure post</b> with a routine <b>r</b>, the class tells its clients:


Programming by Contract is a way of specifying the behavior of a function, and the name arises from its formal similarity to a legal contract. The preconditions define the conditions whose truth the caller guarantees to ensure before calling the function, and the postconditions define the conditions whose truth the function guarantees to establish by virtue of its execution. One of the purposes in this is to avoid redundant validity checks at each level in a stack of called functions.  
If you promise to call ''r'' with ''pre'' satisfied then I, in return, promise to deliver a final state in which ''post'' is satisfied.
 


Design by contract is characterized by at least four simple assertion mechanisms. Here are some examples example written in the syntax in C++.


1. It is possible to describe function preconditions, that is, logical conditions that the implementer of the function expects to be true when the function is called.


===Consider the following example: ===
<pre>
<pre>
Example:
Stack Example: [1]
              double sqrt( double r )
              in // start a block with preconditions
              {
                    r > 0.0: throw bad_input();
              }
              do // normal function body
              { ... }


The precondition is read as "if r > 0.0, continue; otherwise throw an exception".
class STACK [G] feature 
...Declaration of the features:
    count, empty, full, put, remove, item
end
</pre>
</pre>
Before considering implementation issues, however, it is important to note that the routines are characterized by strong semantic properties, independent of any specific representation. <br>
For example:<br>
• Routines <b>remove</b> and <b>item</b> are only applicable if the number of elements is not zero.<br>
• <b>put</b> increases the number of elements by one; <b>remove</b> decreases it by one.
<br>
Such properties are part of the abstract data type specification, and even people who do not use any approach remotely as formal as ADTs understand them implicitly. But in common approaches to software  construction software texts reveal no trace of them. Through routine preconditions and postconditions you can turn them into explicit elements of the software.
<br>


2. It is possible to describe function postconditions, that is, logical conditions that the implementer of the function expects to be true when the function has ended normally.
We will express preconditions and postconditions as clauses of routine declarations
introduced by the keywords require and ensure respectively. For the stack class, leaving
the routine implementations blank, this gives [1]:


<pre>
<pre>
Example:
Stack Example: [1]
                 int foo( int& i )
 
                 out // start block with postconditions
class STACK1 [G] feature -- Access
                 {
    count: INTEGER
                    i == in i + 1;
            -- Number of stack elements
                    return % 2 == 0;
    item: G is
                 }
                 -- Top element
                do // normal function body
            require
                {
            not empty
                    i++;
            do
                    return 4;
              ....
                }
            end
 
feature -- Status report
    empty: BOOLEAN is
                 -- Is stack empty?
            do
              ....
            end
 
    full: BOOLEAN is
                 -- Is stack representation full?
            do
              ....   
            end
 
feature -- Element change
    put (x: G) is
                 -- Add x on top.
            require
                not full
            do
                ....
            ensure
                not empty
                item = x
                count = old count + 1
            end


The idea is that in i means the value of the expression i before the function body is evaluated. return is a
    remove is
special variable that equals the result of the function if it exits normally. (Remark: in Eiffel i == in i + 1
                  -- Remove top element.
would be written i = old i + 1.)
            require
                not empty
            do
                ....
            ensure
                not full
                count = old count – 1
            end
end
</pre>
</pre>


3. It is possible to describe class invariants, that is, logical conditions that the implementer of the class expects to be true after the constructor has executed successfully and before and after any execution of a       public member function.  
Both the require and the ensure clauses are optional; when present, they appear at
the places shown. The require appears before the local clause, if present.
<br>
 
<b>Preconditions: </b>
A precondition expresses the constraints under which a routine will function properly.
<br>
Here: <br>
• '''put''' may not be called if the stack representation is full.<br>
• '''remove''' and '''item''' may not be applied to an empty stack. <br>
 
A precondition applies to all calls of the routine, both from within the class and from
clients. A correct system will never execute a call in a state that does not satisfy the
precondition of the called routine.
<br>
<br>
<b>Postconditions</b>
A postcondition expresses properties of the state resulting from a routine’s execution.
<br>
Here: <br>
• After a '''put''', the stack may not be empty, its top is the element just pushed, and its
number of elements has been increased by one. <br>
• After a '''remove''', the stack may not be full, and its number of elements has been
decreased by one. <br>
The presence of a postcondition clause in a routine expresses a guarantee on the part
of the routine’s implementor that the routine will yield a state satisfying certain properties,
assuming it has been called with the precondition satisfied.
<br><br>
A precondition-postcondition pair for a routine will describe the contract that the
routine (the supplier of a certain service) defines for its callers (the clients of that service).
<br>
The following will be true for contracts between classes:<br>
• The precondition binds the client: it defines the conditions under which a call to the
routine is legitimate. It is an obligation for the client and a benefit for the supplier. <br>
• The postcondition binds the class: it defines the conditions that must be ensured by
the routine on return. It is a benefit for the client and an obligation for the supplier. <br>
<br>
The benefits are, for the client, the guarantee that certain properties will hold after
the call; for the supplier, the guarantee that certain assumptions will be satisfied whenever
the routine is called. The obligations are, for the client, to satisfy the requirements as stated
by the precondition; for the supplier, to do the job as stated by the postcondition.
Here is the contract for one of the routines in stack example: <br><br>
'''A routine contract: routine 'put' for stack class''' <br>
 
<table border="1">
<tr>
<th> </th>
<th>OBLIGATIONS</th>
<th>BENEFITS</th>
</tr>
<tr>
<td>Client</td>
<td>(Satisfy precondition:)<br>
Only call put (x) on a nonfull stack.</td>
<td>(From postcondition:)<br>
Get stack updated: not empty, x on top (item yields x, count increased by 1).</td>
</tr>
<tr>
<td> Supplier </td>
<td>(Satisfy postcondition:)<br>
Update stack representation to have x on top (item yields x), count increased by 1, not empty.</td>
<td>(From precondition:) <br>
Simpler processing thanks to the assumption that stack is not full.</td>
</tr>
</table>
 
<br>
 
== Other useful examples ==
=== Design By Contract for Java ===
Contracts for Java (C4J) is a Design By Contract (DBC) framework for Java 1.5 and later.  
<br>Some of the examples are as follows: [2]


==== Class invariant example ====
<pre>
<pre>
Example:
@ContractReference(contractClassName = "DummyContract")
                                       
  public class Dummy
              class container
  {
              {
    protected double m_divisor;
                    // ...
 
                    invariant
    public Dummy(double divisor)
                    {
    {
                        size() >= 0;
      m_divisor = divisor;
                        size() <= max_size();
    }
                        is_empty() implies size() == 0;
 
                        is_full() implies size() == max_size();
    public double divide(double x)
                        distance( begin(), end() ) == size();
    {
                      }
      return x / m_divisor;
              };
    }
  }
---------------------------------------------------------
  public class DummyContract
  {
    Dummy m_target;


The last assertion is an example of a constraint that is infeasible even in debug code if random-access iterators
    public DummyContract(Dummy target)
are not supported. Invariants are inherited and can never be weaker in a derived class.
    {
</pre>
      m_target = target;
    }


4. It is possible to formalize the notion of overriding a virtual function; the idea can be justified by substitution principles and is referred to as subcontracting. Subcontracting consists of two simple rules that the      overriding function must obey [Mey97].
    public void classInvariant()
  (1) the precondition cannot be stronger, and
    {
  (2) the postcondition cannot be weaker.
      assert m_target.m_divisor != 0;
<pre>
    }
Example:
  }
              void Base::foo( int i ) in { i > 5; } do { ... }
              void Derived::foo( int i )            do { ... }
              Base& b = *new Derived;
              b.foo( 5 ); // will trigger assertion


Thus the compiler will automatically OR preconditions from the base class function with the preconditions of the
The Dummy class constructor in this example makes an assumption that parameter divisor is never 0.
overriding function and it will automatically AN D postconditions from the base class function with the
This is verified by the classInvariant method in the DummyContract class. The contract is tied to
postconditions of the overriding function. Once a programmer has specified contracts, the language provides a
the target using an annotation. The contract has a constructor that takes an argument of the target
mechanism for checking whether the conditions hold at run-time and a mechanism to turn off this run-time check for
type. The contractClassName attribute of the ContractReference annotation does not have to be fully
the sake of efficiency.
qualified if the contract class is implemented in the same package as the target class.
</pre>
</pre>


=== Some other useful examples ===
==== Pre condition example ====
==== Example 1 ====
<pre>
Consider the following example for counting the number of vowles [1]:
  @ContractReference(contractClassName = "DummyContract")
  public class Dummy
  {
    public double divide(double x, double y)
    {
      return x / y;
    }
  }
---------------------------------------------------------------
  public class DummyContract
  {
    public void classInvariant()
    {
      // Nothing to do here
    }


<pre>
    public void pre_divide(double x, double y)
int is_vowelpair (const char *p)
    {
{
      assert y != 0;
     return is_vowel(*p) && is_vowel (*(p+1));
     }
}
  }


int count_vowelpairs (char *s)
In this example, in the divide method, it is assumed that the value of y will never be 0.
{
This is verified in the pre_divide method in the DummyContract class.
    int sum = 0;
   
    for (; *s != '\0'; s++)
        if (is_vowelpair(s))
            sum++;
    return sum;
}
</pre>
</pre>


The functions count_vowelpairs receive as input argument a pointer to a C string. Neither function applies any validity check to the pointer, so there is an implicit precondition that the caller supply a valid pointer. To follow the rules of programming by contract we should make this an explicit precondition, albeit one that is so common and obvious that it hardly seems to need stating.
====Interface example====
<pre>
  @ContractReference(contractClassName = "DummyContract")
  public interface Dummy
  {
    double divide(double x, double y);
  }
------------------------------------------------------------
  public class DummyContract extends ContractBase<Dummy>
  {
    public DummyContract(Dummy target)
    {
      super(target);
    }


There are four possibilities for the pointer passed in as argument:
    public void pre_divide(double x, double y)
    {
      assert y != 0;
    }


It contains a valid address that is indeed the address of a valid C string (including the null string).
    public void post_divide(double x, double y)
It contains a valid address but the memory at that address does not comprise a valid C string.
    {
It contains a bit pattern that is not a valid address (e.g., it is outside the addressing range, or the memory is not readable).
      assert getReturnValue() == x / y;
It contains the null pointer.
    }
Our contract imposes the precondition that the pointer must be valid as specified in the first case above. There is no reasonable way to detect the second case, and for the third case it is usual to delegate detection (and handling) to the exception mechanism of the operating system11.
  }
 
The fourth case is the interesting one. Null is a valid value for a pointer, but it is (by definition) an invalid address that will generally cause an addressing exception if dereferenced. It is, however, trivial for the function to detect that a null pointer argument has been passed. Therefore, we can propose a general rule that makes life easier for callers of a function: If a pointer to a null object is a valid argument, a null pointer should also be a valid argument with the same meaning. In the specific examples we are studying here, we should change the contract by weakening the precondition to allow the first and fourth cases, and implement the function to immediately return the value 0 if a null pointer is passed as the argument. The purpose of this rule is to relieve callers of the need to make the test for a null pointer; for a language like C the gain is not obvious, but for functional style languages like Lisp the gain is significant.


In this example, the contract will verify that all the usages of the divide interface meets the
precondition, and that all implementations of the interface will meet the post condition.
</pre>


==== Example 2 ====
===Design by Contract Programming in C++===
Consider the following sort function in python [3]:
The material in this section has been taken from: [3]
====Design by Contract Framework====
<pre>
<pre>
def sort(a):
// Object class is the base class for all
     """Sort a list *IN PLACE*.
// objects in the system. All classes inheriting from this class need
// to define a method IsValid. This method should perform a
// consistency check on the state of the object. Note that
// this method needs to be defined only when a debug build is made
class Object
{
public:
#ifdef _DEBUG
    bool IsValid() const = 0;
#endif
      
};


    pre:
#ifdef _DEBUG
        # must be a list
        isinstance(a, list)


        # all elements must be comparable with all other items
// The debug mode also defines the following macros. Failure of any of these macros leads to
        forall(range(len(a)),
// program termination. The user is notified of the error condition with the right file name
              lambda i: forall(range(len(a)),
// and line number. The actual failing operation is also printed using the stringizing operator #
                                lambda j: (a[i] < a[j]) ^ (a[i] >= a[j])))


    post[a]:
#define ASSERT(bool_expression) if (!(bool_expression)) abort_program(__FILE__, __LINE__, #bool_expression)
        # length of array is unchanged
#define IS_VALID(obj) ASSERT((obj) != NULL && (obj)->IsValid())
        len(a) == len(__old__.a)
#define REQUIRE(bool_expression) ASSERT(bool_expression)
#define ENSURE(bool_expression) ASSERT(bool_expression)


        # all elements given are still in the array
#else
        forall(__old__.a, lambda e: __old__.a.count(e) == a.count(e))


        # the array is sorted
// When built in release mode, the _DEBUG flag would not be defined, thus there will be no overhead
        forall([a[i] >= a[i-1] for i in range(1, len(a))])
// in the final release from these checks.
</pre>
This tells us everything we need to know about sort. During debugging, these statements are actually executed. If any of the pre-conditions are false, an exception is raised so the caller can be debugged. If any of the post-conditions are false, a similar exception is raised so the sort function can be debugged.


#define ASSERT(ignore) ((void) 0)
#define IS_VALID(ignore) ((void) 0)
#define REQUIRE(ignore) ((void) 0)
#define ENSURE(ignore) ((void) 0)


A programming language called Eiffel was created to facilitate Design by Contract. Eiffel provides built-in features to support the implementation of Design by Contract. The example below illustrates those features: [4]
#endif
</pre>


==== Example 3 ====
====Example: Terminal Manager====
Terminal Manager exemplifies a typical design pattern seen in embedded systems. Here a collection of terminals is being managed by the Terminal Manager. Management involves routing messages, creating and deleting terminals. <br>
The Terminal Manager implements the following methods: <br>
    a)'''Add_Terminal''': Create and add a new terminal<br>
    b)'''Remove_Terminal''': Remove and delete a terminal<br>
    c)'''Find_Terminal''': Find a terminal from its terminal_Id<br>
    d)'''Handle_Message''': Route the received message to the Terminal object<br>


The following example shows a partial implementation of a bounded queue, with methods put and remove. The pre- and post-conditions for those methods are coded explicitly with the "require" and "ensure" features of Eiffel.


<pre>
<pre>
                class BoundedQueue[G] feature
#include <map>      // Header file include for map
                    put(x:G) is
using std;         // STL containers are defined in std namespace
                      -- add x as newest element
                      require
                          not full
                      do
                          -- implementation of put
                          . . .
                      ensure
                          not empty
                      end;
                    remove is
                      -- remove oldest element
                      require
                          not empty
                      do
                          -- implementation of remove
                          . . .
                      ensure
                          not full
                      end;
                          empty: BOOLEAN is
                              -- is the queue empty?
                              do Result:=. . . end;
                          full: BOOLEAN is
                              -- is the queue full?
                              do Result:=. . . end;
                      end
</pre>


The assertions are checked at run-time. This checking can be turned on or off as a result of a compilation switch.
class TerminalManager : public Object
{
  // The map is keyed with the terminal id and stores pointers to Terminals.
  // terminal id is an integer, terminal ids can be in the entire range for
  // an integer and they will still be efficiently stored inside a map.
  typedef map<int, Terminal *> TerminalMap;
  TerminalMap m_terminalMap;
  int m_managerType;
  FaultManager m_faultManager;


==== Example 4 ====
public:
The following is an example of how Programming by Contract can be implemented in C++ [5]:


The first precondition could be called a default precondition. It should be possible to remove such preconditions from object code. However, the second and the third precondition must always be part of the object code.  
#ifdef _DEBUG
  // IsValid methods play an important role in checking the consistency
  // of objects in the debug. IsValid is defined as a pure virtual function
  // in Object class, thus it needs to be overriden in all inheriting classes.
  // The inheriting class should perform defensive checks to make
  // sure that it is in a consistent state/
  // Also note that this method is only available in the debug build.
  virtual bool IsValid() const
  {
      return (m_terminalMap.count() <= MAX_TERMINALS_PER_MANAGER &&
              m_managerType < MAX_MANAGER_TYPES &&
              m_faultManager.IsValid()); 
  }
 
#endif


int not_ok( int& );
  Status AddTerminal(int terminalId, int type)
int ok( int );
  {
struct Foo { int foo(); int bar() const; };
      // Checking Preconditions
Foo f;
      REQUIRE(terminalId < MAX_TERMINAL_ID);
Foo* f_ptr;
      REQUIRE(type >= TERMINAL_TYPE_RANGE_MIN && type <= TERMINAL_TYPE_RANGE_MAX);
...
     
void foo( int i )
      Status status;
in
     
{
      // Check if the terminal is already present in the map. count()
not_ok( i ); // error: ’not_ok()’ takes a reference argument
      // returns the total number of entries that are keyed by terminalId
ok( i ); // ok: ’ok()’ takes a value argument
      if(m_terminalMap.count(terminalId) == 0)
f.foo(); // error: cannot call a non-const member
      {
f_ptr->foo(); // error: not even through a pointer
        // count() returned zero, so no entries are present in the map
f_ptr->bar(); // ok: bar is a const member function
        Terminal *pTerm = new Terminal(terminalId, type);
f_ptr; // ok: conversion to bool
"a comment"; // ok: conversion to bool
        // Make sure that the newly created terminal is in consistent state
if( ... ); // error: statements not allowed
        IS_VALID(pTerm);
i = 2; // error: assignment not possible
       
i > 0; return FAILURE_CODE; // error: ’return’ not allowed
        // Since map overloads the array operator [ ], it gives
}
        // the illusion of indexing into an array. The following
        // line makes an entry into the map
        m_terminalMap[termId] = pTerm;
       
        status = SUCCESS;
      }
      else
      {
        // count() returned a non zero value, so the terminal is already
        // present.
        status = FAILURE;
      }
     
      // Checking post conditions:
      // 1. TerminalManager should be consistent
      // 2. The new terminal should always be found
      // 3. The manager should not be controlling more terminals
      //    than allowed
      // 4. Make sure correct return code is being returned.
      IS_VALID(this);
      ENSURE(FindTerminal(termId));
      ENSURE(m_terminalMap.count() <= MAX_TERMINALS_PER_MANAGER));
      ENSURE(status == SUCCESS || status == FAILURE);
      return status;
  }
 
  Status RemoveTerminal(int terminalId)
  {
      // Check pre-conditions
      // Note: Here the REQUIRE macro makes sure that
      // terminal to be deleted is actually present. A similar
      // check will be done in the main body of the code.
      // The duplicate check in the REQUIRE macro allows flagging
      // the error earlier.


Postconditions are much like preconditions: (1) they are optional, (2) can include throw clauses (which are never compiled away), and (3) has the same rules regarding const-correctness. Note that postconditions are only checked when the function exits normally.
      REQUIRE(terminalId < MAX_TERMINAL_ID);
      REQUIRE(FindTerminal(terminalId));
     
      Status status;
      // Check if the terminal is present
      if (m_terminalMap.count(terminalId) == 1)
      {
        // Save the pointer that is being deleted from the map
        Terminal *pTerm = m_terminalMap[terminalId];
     
        // Make sure that terminal object being deleted is in a consistent
        // state
        IS_VALID(pTerm);       
 
        // Erase the entry from the map. This just frees up the memory for
        // the pointer. The actual object is freed up using delete
        m_terminalMap.erase(terminalId);
        delete pTerm;
       
        status = SUCCESS;
      }
      else
      {
        status = FAILURE;
      }


int foo( int& i )
      // Checking Post-conditions:
out
      // 1. Terminal has been successfully deleted (terminal find
{
      //    should return NULL)
i == in i + 1; // keep track of changes to ’i’
      // 2. Only valid status should be returned.
return == 5: terminate(); // call ’terminate()’ on failure
      // 3. Terminal Manager is in a consistent state
}
      ENSURE(FindTerminal(terminalId) == NULL);
do
      ENSURE(status == SUCCESS || status == FAILURE);
{
      IS_VALID(this);    
++i;
     
if( i % 2 == 0 )
      return status;
return 5;
  }
else
 
return 4;
  // Find the terminal for a given terminal id, return
}
  // NULL if terminal not found
Programming by contract places responsibility squarely on the shoulders of the caller for ensuring that specified preconditions for a function are met, and relieves the function of any responsibility for verifying that preconditions are met. As intended, this has the desirable effect of eliminating redundant validity checking. In real life, however, it also has an undesirable side effect: If the caller makes a mistake and does not in fact meet the preconditions, the function is likely to fail, and the cause of the failure may be difficult to track down. A pointer that is null or contains an invalid address is usually easy to diagnose; since an exception will be caused immediately an attempt is made to deference it, but other errors may cause failures far removed from the root cause.
  Terminal *FindTerminal(int terminalId)
  {
    Terminal *pTerm;
    if (m_terminalMap.count(terminalId) == 1)
    {
        pTerm = m_terminalMap[terminalId];
    }
    else
    {
        pTerm = NULL;
    }
   
    return pTerm;
  }  
 
  void HandleMessage(const Message *pMsg)
  {
    // Check pre-conditions:
    IS_VALID(pMsg);
    ENSURE(FindTerminal(pMsg->GetTerminal()));
   
    int terminalId = pMsg->GetTerminalId();
   
    Terminal *pTerm;
   
    pTerm = FindTerminal(terminalId);
   
    if (pTerm)
    {
        pTerm->HandleMessage(pMsg);
    }   
  }
};
</pre>


== See Also ==
== More good examples can be found at the sites mentioned below ==
http://en.wikibooks.org/wiki/Computer_programming/Design_by_Contract<br>
http://en.wikibooks.org/wiki/Computer_programming/Design_by_Contract<br>
http://www.eventhelix.com/RealtimeMantra/Object_Oriented/design_by_contract.htm<br>
http://www.eventhelix.com/RealtimeMantra/Object_Oriented/design_by_contract.htm<br>
Line 234: Line 480:
http://www.artima.com/cppsource/deepspace2.html<br>
http://www.artima.com/cppsource/deepspace2.html<br>
http://java.sun.com/j2se/1.4.2/docs/guide/lang/assert.html<br>
http://java.sun.com/j2se/1.4.2/docs/guide/lang/assert.html<br>
http://www.csc.calpoly.edu/~dstearns/SeniorProjectsWWW/Rideg/dbc.html
http://www.csc.calpoly.edu/~dstearns/SeniorProjectsWWW/Rideg/dbc.html<br>
http://taipei-jackie.info/Slides/presentation_slides_2.ppt<br>
http://www.ibm.com/developerworks/rational/library/455.html#N10324 <br>
http://www.wayforward.net/pycontract/ <br>
http://www.patentstorm.us/patents/6442750-description.html<br>
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n1613.pdf


== References ==
== References ==
[1] http://www.ibm.com/developerworks/rational/library/455.html#N10324 <br>
[1] Object-Oriented Software Construction SECOND EDITION. <br>
[2] http://archive.eiffel.com/doc/manuals/technology/contract/page.html <br>
[2] http://c4j.sourceforge.net/ <br>
[3] http://www.wayforward.net/pycontract/ <br>
[3] http://www.eventhelix.com/RealtimeMantra/Object_Oriented/design_by_contract.htm <br>
[4] http://www.patentstorm.us/patents/6442750-description.html<br>
[5] http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n1613.pdf

Latest revision as of 23:46, 28 November 2007

Topic:
In class, we had some difficulty coming up with good examples of programming by contract. Find some concise ones that illustrate the principle well, and are accessible to a general audience of programmers.

Please note that as per the assignment requirement, we need to find good examples of programming by contract. So all the material and examples in this wiki has been taken from outside sources.

Programming by contract

Programming by Contract is a way of specifying the behavior of a function, and the name arises from its formal similarity to a legal contract. The key concept is viewing the relationship between a class and its clients as a formal agreement, expressing each party’s rights and obligations. Defining a precondition and a postcondition for a routine is a way to define a contract that binds the routine and its callers. The precondition states the properties that must hold whenever the routine is called; the postcondition states the properties that the routine guarantees when it returns.
By associating clauses require pre and ensure post with a routine r, the class tells its clients:

If you promise to call r with pre satisfied then I, in return, promise to deliver a final state in which post is satisfied.


Consider the following example:

Stack Example: [1]

class STACK [G] feature  
 ...Declaration of the features:
    count, empty, full, put, remove, item
end

Before considering implementation issues, however, it is important to note that the routines are characterized by strong semantic properties, independent of any specific representation.

For example:
• Routines remove and item are only applicable if the number of elements is not zero.
put increases the number of elements by one; remove decreases it by one.

Such properties are part of the abstract data type specification, and even people who do not use any approach remotely as formal as ADTs understand them implicitly. But in common approaches to software construction software texts reveal no trace of them. Through routine preconditions and postconditions you can turn them into explicit elements of the software.

We will express preconditions and postconditions as clauses of routine declarations introduced by the keywords require and ensure respectively. For the stack class, leaving the routine implementations blank, this gives [1]:

Stack Example: [1]

class STACK1 [G] feature -- Access
     count: INTEGER
            -- Number of stack elements
     item: G is
                 -- Top element
            require
            not empty
            do
               .... 
            end

feature -- Status report
     empty: BOOLEAN is
                 -- Is stack empty?
            do 
               ....
            end

     full: BOOLEAN is
                 -- Is stack representation full?
            do
               ....     
            end

feature -- Element change
     put (x: G) is
                 -- Add x on top. 
            require
                not full
            do
                .... 
            ensure
                not empty
                item = x
                count = old count + 1
            end

     remove is
                  -- Remove top element.
            require
                not empty
            do
                .... 
            ensure
                not full
                count = old count – 1
            end
end

Both the require and the ensure clauses are optional; when present, they appear at the places shown. The require appears before the local clause, if present.

Preconditions: A precondition expresses the constraints under which a routine will function properly.
Here:
put may not be called if the stack representation is full.
remove and item may not be applied to an empty stack.

A precondition applies to all calls of the routine, both from within the class and from clients. A correct system will never execute a call in a state that does not satisfy the precondition of the called routine.

Postconditions A postcondition expresses properties of the state resulting from a routine’s execution.
Here:
• After a put, the stack may not be empty, its top is the element just pushed, and its number of elements has been increased by one.
• After a remove, the stack may not be full, and its number of elements has been decreased by one.
The presence of a postcondition clause in a routine expresses a guarantee on the part of the routine’s implementor that the routine will yield a state satisfying certain properties, assuming it has been called with the precondition satisfied.

A precondition-postcondition pair for a routine will describe the contract that the routine (the supplier of a certain service) defines for its callers (the clients of that service).
The following will be true for contracts between classes:
• The precondition binds the client: it defines the conditions under which a call to the routine is legitimate. It is an obligation for the client and a benefit for the supplier.
• The postcondition binds the class: it defines the conditions that must be ensured by the routine on return. It is a benefit for the client and an obligation for the supplier.

The benefits are, for the client, the guarantee that certain properties will hold after the call; for the supplier, the guarantee that certain assumptions will be satisfied whenever the routine is called. The obligations are, for the client, to satisfy the requirements as stated by the precondition; for the supplier, to do the job as stated by the postcondition. Here is the contract for one of the routines in stack example:

A routine contract: routine 'put' for stack class

OBLIGATIONS BENEFITS
Client (Satisfy precondition:)
Only call put (x) on a nonfull stack.
(From postcondition:)
Get stack updated: not empty, x on top (item yields x, count increased by 1).
Supplier (Satisfy postcondition:)
Update stack representation to have x on top (item yields x), count increased by 1, not empty.
(From precondition:)
Simpler processing thanks to the assumption that stack is not full.


Other useful examples

Design By Contract for Java

Contracts for Java (C4J) is a Design By Contract (DBC) framework for Java 1.5 and later.
Some of the examples are as follows: [2]

Class invariant example

 @ContractReference(contractClassName = "DummyContract")
  public class Dummy
  {
    protected double m_divisor;

    public Dummy(double divisor)
    {
      m_divisor = divisor;
    }

    public double divide(double x)
    {
      return x / m_divisor;
    }
  }
---------------------------------------------------------
  public class DummyContract
  {
    Dummy m_target;

    public DummyContract(Dummy target)
    {
      m_target = target;
    }

    public void classInvariant()
    {
      assert m_target.m_divisor != 0;
    }
  }

The Dummy class constructor in this example makes an assumption that parameter divisor is never 0.
This is verified by the classInvariant method in the DummyContract class. The contract is tied to
the target using an annotation. The contract has a constructor that takes an argument of the target
type. The contractClassName attribute of the ContractReference annotation does not have to be fully
qualified if the contract class is implemented in the same package as the target class.

Pre condition example

  @ContractReference(contractClassName = "DummyContract")
  public class Dummy
  {
    public double divide(double x, double y)
    {
      return x / y;
    }
  }
---------------------------------------------------------------
  public class DummyContract
  {
    public void classInvariant()
    {
      // Nothing to do here
    }

    public void pre_divide(double x, double y)
    {
      assert y != 0;
    }
  }

In this example, in the divide method, it is assumed that the value of y will never be 0. 
This is verified in the pre_divide method in the DummyContract class.

Interface example

  @ContractReference(contractClassName = "DummyContract")
  public interface Dummy
  {
    double divide(double x, double y);
  }
------------------------------------------------------------
  public class DummyContract extends ContractBase<Dummy>
  {
    public DummyContract(Dummy target)
    {
      super(target);
    }

    public void pre_divide(double x, double y)
    {
      assert y != 0;
    }

    public void post_divide(double x, double y)
    {
      assert getReturnValue() == x / y;
    }
  }

In this example, the contract will verify that all the usages of the divide interface meets the
precondition, and that all implementations of the interface will meet the post condition.

Design by Contract Programming in C++

The material in this section has been taken from: [3]

Design by Contract Framework

// Object class is the base class for all
// objects in the system. All classes inheriting from this class need 
// to define a method IsValid. This method should perform a
// consistency check on the state of the object. Note that 
// this method needs to be defined only when a debug build is made
class Object
{
public:
#ifdef _DEBUG
    bool IsValid() const = 0;
#endif
    
};

#ifdef _DEBUG

// The debug mode also defines the following macros. Failure of any of these macros leads to
// program termination. The user is notified of the error condition with the right file name
// and line number. The actual failing operation is also printed using the stringizing operator #

#define ASSERT(bool_expression) if (!(bool_expression)) abort_program(__FILE__, __LINE__, #bool_expression)
#define IS_VALID(obj) ASSERT((obj) != NULL && (obj)->IsValid())
#define REQUIRE(bool_expression) ASSERT(bool_expression)
#define ENSURE(bool_expression) ASSERT(bool_expression)

#else

// When built in release mode, the _DEBUG flag would not be defined, thus there will be no overhead
// in the final release from these checks.

#define ASSERT(ignore) ((void) 0)
#define IS_VALID(ignore) ((void) 0) 
#define REQUIRE(ignore) ((void) 0)
#define ENSURE(ignore) ((void) 0)

#endif

Example: Terminal Manager

Terminal Manager exemplifies a typical design pattern seen in embedded systems. Here a collection of terminals is being managed by the Terminal Manager. Management involves routing messages, creating and deleting terminals.
The Terminal Manager implements the following methods:

   a)Add_Terminal: Create and add a new terminal
b)Remove_Terminal: Remove and delete a terminal
c)Find_Terminal: Find a terminal from its terminal_Id
d)Handle_Message: Route the received message to the Terminal object


#include <map>      // Header file include for map
using std;          // STL containers are defined in std namespace

class TerminalManager : public Object
{
   // The map is keyed with the terminal id and stores pointers to Terminals.
   // terminal id is an integer, terminal ids can be in the entire range for
   // an integer and they will still be efficiently stored inside a map.
   typedef map<int, Terminal *> TerminalMap;
   TerminalMap m_terminalMap;
   int m_managerType;
   FaultManager m_faultManager;

public:

#ifdef _DEBUG
   // IsValid methods play an important role in checking the consistency
   // of objects in the debug. IsValid is defined as a pure virtual function
   // in Object class, thus it needs to be overriden in all inheriting classes.
   // The inheriting class should perform defensive checks to make
   // sure that it is in a consistent state/
   // Also note that this method is only available in the debug build.
   virtual bool IsValid() const
   {
       return (m_terminalMap.count() <= MAX_TERMINALS_PER_MANAGER &&
               m_managerType < MAX_MANAGER_TYPES &&
               m_faultManager.IsValid());  
   }
   
#endif

   Status AddTerminal(int terminalId, int type)
   {
      // Checking Preconditions
      REQUIRE(terminalId < MAX_TERMINAL_ID);
      REQUIRE(type >= TERMINAL_TYPE_RANGE_MIN && type <= TERMINAL_TYPE_RANGE_MAX);
      
      Status status;
      
      // Check if the terminal is already present in the map. count()
      // returns the total number of entries that are keyed by terminalId
      if(m_terminalMap.count(terminalId) == 0)
      {
         // count() returned zero, so no entries are present in the map
         Terminal *pTerm = new Terminal(terminalId, type);
 
         // Make sure that the newly created terminal is in consistent state
         IS_VALID(pTerm);
         
         // Since map overloads the array operator [ ], it gives 
         // the illusion of indexing into an array. The following
         // line makes an entry into the map
         m_terminalMap[termId] = pTerm;
         
         status = SUCCESS;
      }
      else
      {
         // count() returned a non zero value, so the terminal is already
         // present.
         status = FAILURE;
      }
      
      // Checking post conditions:
      // 1. TerminalManager should be consistent
      // 2. The new terminal should always be found
      // 3. The manager should not be controlling more terminals
      //    than allowed
      // 4. Make sure correct return code is being returned.
      IS_VALID(this);
      ENSURE(FindTerminal(termId));
      ENSURE(m_terminalMap.count() <= MAX_TERMINALS_PER_MANAGER));
      ENSURE(status == SUCCESS || status == FAILURE);
      return status;
   }
   
   Status RemoveTerminal(int terminalId)
   {
      // Check pre-conditions
      // Note: Here the REQUIRE macro makes sure that
      // terminal to be deleted is actually present. A similar
      // check will be done in the main body of the code.
      // The duplicate check in the REQUIRE macro allows flagging
      // the error earlier.

      REQUIRE(terminalId < MAX_TERMINAL_ID);
      REQUIRE(FindTerminal(terminalId));
      
      Status status;
      // Check if the terminal is present
      if (m_terminalMap.count(terminalId) == 1)
      {
         // Save the pointer that is being deleted from the map
         Terminal *pTerm = m_terminalMap[terminalId]; 
      
         // Make sure that terminal object being deleted is in a consistent
         // state
         IS_VALID(pTerm);         
   
         // Erase the entry from the map. This just frees up the memory for
         // the pointer. The actual object is freed up using delete
         m_terminalMap.erase(terminalId);
         delete pTerm;
         
         status = SUCCESS;
      }
      else
      {
         status = FAILURE;
      }

      // Checking Post-conditions:
      // 1. Terminal has been successfully deleted (terminal find
      //    should return NULL)
      // 2. Only valid status should be returned.
      // 3. Terminal Manager is in a consistent state
      ENSURE(FindTerminal(terminalId) == NULL);
      ENSURE(status == SUCCESS || status == FAILURE);
      IS_VALID(this);     
      
      return status;
   }
  
  // Find the terminal for a given terminal id, return
  // NULL if terminal not found
  Terminal *FindTerminal(int terminalId)
  {
     Terminal *pTerm;
     if (m_terminalMap.count(terminalId) == 1)
     {
        pTerm = m_terminalMap[terminalId];
     }
     else
     {
         pTerm = NULL;
     }
     
     return pTerm;
  } 
  
  void HandleMessage(const Message *pMsg)
  {
     // Check pre-conditions:
     IS_VALID(pMsg);
     ENSURE(FindTerminal(pMsg->GetTerminal()));
     
     int terminalId = pMsg->GetTerminalId();
     
     Terminal *pTerm;
     
     pTerm = FindTerminal(terminalId);
     
     if (pTerm)
     {
        pTerm->HandleMessage(pMsg);
     }    
  }
};

More good examples can be found at the sites mentioned below

http://en.wikibooks.org/wiki/Computer_programming/Design_by_Contract
http://www.eventhelix.com/RealtimeMantra/Object_Oriented/design_by_contract.htm
http://www.cs.uno.edu/~c1581/Labs2006/lab7/lab7.htm
http://www.phpunit.de/pocket_guide/3.2/en/test-first-programming.html
http://www.python.org/dev/peps/pep-0316/
http://www.artima.com/cppsource/deepspace2.html
http://java.sun.com/j2se/1.4.2/docs/guide/lang/assert.html
http://www.csc.calpoly.edu/~dstearns/SeniorProjectsWWW/Rideg/dbc.html
http://taipei-jackie.info/Slides/presentation_slides_2.ppt
http://www.ibm.com/developerworks/rational/library/455.html#N10324
http://www.wayforward.net/pycontract/
http://www.patentstorm.us/patents/6442750-description.html
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n1613.pdf

References

[1] Object-Oriented Software Construction SECOND EDITION.
[2] http://c4j.sourceforge.net/
[3] http://www.eventhelix.com/RealtimeMantra/Object_Oriented/design_by_contract.htm