Formal specification

A formal specification of the behavior of an object may be given by defining a pre-condition and post-condition for each method. The pre-condition of a method specifies in a logical manner what restrictions the client invoking a particular method is obliged to comply with. When the client fails to meet these requirements the result of the method will be undefined. In effect, after the violation of a pre-condition anything can happen. Usually, this means that the computation may be aborted or that some other means of error-handling may be started. For instance, when the implementation language supports exceptions an exception handler may be invoked. The post-condition of a method states what obligations the server object has when executing the method, provided that the client's request satisfies the method's pre-condition. Apart from specifying a pre-condition and post-condition for each method publicly supported by the class, the designer of the class may also specify a class invariant, to define the invariant properties of the state of each instance of the class. A class annotated with an invariant and pre- and post-conditions for the methods may be regarded as a contract, since it specifies precisely (in an abstract way) the behavioral conformance conditions of the object and the constraints imposed on the interactions between the object and its clients. See slide 3-obligations.

Contractual obligations

clientsupplier
pre-conditionobligationbenefit
post-conditionbenefitobligation

slide: Contractual obligations


Assertions -- formal specification


slide: Formal specification of contracts

Intuitively, contracts have a clear analogy to our business affairs in everyday life. For instance, when buying audio equipment, as a client you wish to know what you get for the price you pay, whereas the dealer may require that you pay in cash. Following this metaphor through, we see that the supplier may actually benefit from imposing a (reasonable) pre-condition and that the client has an interest in a well-stated post-condition. Most people are not willing to pay without knowing what they will get for their money. The use of contracts was originally proposed by  [Meyer88], and is directly supported by the language Eiffel, which offers the keywords require (to indicate a pre-condition), ensure (to indicate a post-condition) and invariant (to indicate the invariance condition). See slide 3-formal. The Eiffel environment has options to dynamically check any of the three kinds of assertions, even selectively per class. The assertions, except for the invariance condition, are directly embedded in the code. Although less elegant, the same functionality can be achieved in C++ by using the assert macro defined in {\tt assert.h} as explained in section ASSERT, which also introduced the require and promise macros for C++. For dynamically checking the invariance condition, a test should be executed when evaluating the constructor and before and after each method invocation. While a method is being executed, the invariant need not necessarily hold, but it is the responsibility of a method to restore the invariant when it is disrupted. In case object methods are recursively applied, the invariant must be restored when returning to the original caller. An alternative approach to incorporating assertions in a class description is presented in  [Cline], which introduces an extension of C++ called Annotated C++. Instead of directly embedding assertions in the code, Annotated C++ requires the user to specify separately the axioms characterizing the functionality of the methods and their effect on the state of the object. Important from a design perspective is that the specification, even without an implementation of the methods, may be understood as specifying a contract. In practice, they may only be stated as comments.