Design by contract

Design by contract ( DbC short, English for design according to contract ) or Programming by Contract (Contract Based Programming ) is a concept from the field of software development. The objective is the smooth interaction of individual program modules by defining formal " contracts " for use of interfaces that go beyond the static definition. It was developed and introduced by Bertrand Meyer in the development of the programming language Eiffel.

Basic principle

The smooth interaction of program modules is achieved through a "Contract" which must be met, for example in the use of a method. This consists of

  • Preconditions (English precondition ), so the assurances which must comply with the caller
  • Postconditions (English postcondition ), so the assurances which will comply with the callee, and the
  • Invariants (English class invariants ), that the health of a class.

The contract may relate to all of the available information, ie on variables and parameter contents as well as on object states the object concerned or of others of accessible objects. Provided the caller to pre-conditions and invariants holds, no errors can occur and the method provides guaranteed no unexpected results.

A weakened form of contracts is achieved in typed languages ​​already by the typing of input and output parameters. The type shall thereby determine ranges of values ​​that can be interpreted as pre-and postconditions. However, a type of system is not able to detect correlations of several parameters or relationships between input and output values. Therefore, it juxtaposes Design by contract is a significantly weaker form of hedging, but it takes usually at compile time, while the assertions made ​​in contracts only access in case of injury at runtime.

By the definition of class invariants, pre-and postcondition a module can be replaced by any other, when this same "contract" fulfilled. This, however, also utilized identifiers and syntactic details must be regarded as pre-and post if necessary.

Invariants

Invariants are logical statements that apply to all instances of a class over the entire object lifecycle. They usually appear in the form of class invariants that are allowed access to private properties of the affected class. It is therefore also called Implementationsinvarianten. Since verification of invariants in current systems can be done only before and after a method call, invariants may be violated quite temporarily within methods. They thus represent implicit preconditions and postconditions of each method invocation represents an alternative to this approach would be to intercept any variable accesses by means of methods of meta-programming, and thus also to prohibit temporary violations of invariants. This approach is, however, not yet followed in current implementations of design by contract.

Pre-and postconditions

Each subroutine is to be pre-conditions ( preconditions ) and postconditions ( post- conditions ) assigned. The preconditions specify the circumstances under which the subroutine to be called. For example, a subroutine for reading may only be called from a file if the file was previously opened successfully. The postconditions specify the conditions that must be met after completion of the subroutine call.

Pre-and postconditions are formulated as Boolean expressions. Is a prerequisite not satisfied ( ie, its evaluation yields false, so "not applicable" ), there is an error in the calling code: There would have to be taken care of for that the precondition is satisfied. If a post-condition is not satisfied, there is an error in the subroutine itself: The subroutine should have ensured that the postcondition is satisfied.

Therefore, pre-and postcondition form a kind of contract (English contract ): if the calling code satisfies the precondition, then the subroutine is obliged to fulfill the postcondition.

Subklassenbildung and contracts

Liskov'sches substitution principle

Turning to the Liskov Substitution Principle on pre-and postconditions on, we get the following statement:

This means that a method of a subclass when designing their pre-and postconditions is not free: it must at least meet the formulated by the pre-and postconditions "contract". That is, they must not increase the preconditions ( they may not ask for more from the calling code as in the upper class demands ), and it must not weaken the postconditions ( it must guarantee at least as much as the upper class).

Summary of terms and conditions of subclasses

Subclasses must observe the following rules with respect to the upper classes in Design by Contract:

  • Same or stronger invariant
  • Same or weaker preconditions (in terms of methods)
  • Same or stronger postconditions (in terms of methods)

Formally, the relationship of super- and subclass express terms of pre-and postconditions as follows:

Vorbedingungsuper → Vorbedingungsub Nachbedingungsub → Nachbedingungsuper Review of the terms and conditions of subclasses

The fulfillment of the logical implications described in the previous paragraph can be algorithmically very burdensome to verify ( satisfiability ). One therefore engages with current realizations on a trick back:

  • The disjunctive preconditions are linked ( with logical OR ). Thus, the condition of the upper class are only attenuated, but not tightened.
  • The postconditions are conjunctively (logical AND). This allows the postcondition only be exacerbated, but not weakened.
  • Invariants are also conjunctively.

Limitations of the Procedure

Design By Contract can only be applied to software properties that can be formulated as a pre-and postcondition. Terms such as " before routine A routine must have been called B " can be mapped by state variables. This means on the one hand increased effort for the programming of the class, on the other hand, can users refrain from holding such an object equipped permanently under their control, but it can pass it to other functions and afterwards respond to any status changes. Similar conditions as may " routine A calls in its course always on routine B " ( especially in the area of ​​object-oriented important) are taken over and postconditions Modulinvarianten.

Is based on an invariant auxiliary objects, the invariant can be destroyed by aliasing. Become invariants in addition to the beginning of each subroutine checks the destruction of the invariant can indeed be diagnosed reliably before the program meets wrong decisions due to such Invariantenverletzung, but gets the programmer no indication of where the alias was created and in which modification of the auxiliary object invariant was actually destroyed.

If the semantics of a subroutine completely taken in preconditions, postconditions, and Modulinvarianten, we obtain a functional specification of the subprogram in which the actual subroutine could be generated in principle, from the assurances. Such generators can be created from the compiler techniques for functional programming languages ​​; so far shows a driven approach to perfection by Design By Contract on a step to nächstabstrakteren programming methodology.

Language Support

Some less common programming languages ​​such as Eiffel and D support Design by Contract at least partially native, also since Ada Ada, 2012. The. NET Framework contains since version 4, the class System.Diagnostics.Contracts to implement Design by Contract. The Bean Validation concept offers the same possibility, moreover, it has been possible for the Java Bean Validation 1.1, implement pre-and post directly in methods headers using annotation in Java. This was previously already possible via the framework OVal in Java. Other implementations such as GContracts for Groovy APIs used for compiler extensions to add appropriate language elements.

232160
de