Author: Brandon Pearman

The views expressed here are mine alone and do not reflect the view of my employer.

The term "Design by contract" was coined by Bertrand Meyer, which he implemented in his programming language, Eiffel. Design by contract is also known as "contract programming", "programming by contract" and "design-by-contract programming". Often C# interfaces are refered to as contracts but they are quite limited compared to the contracts suggested by Bertrand Meyer and implemented in Eiffel. Design by contract is not just simple interfaces, it includes broader specifications for classes which define mode details about preconditions, postconditions and invariants. It is about setting more detailed contracts/limitations on classes to ensure all uses of the class is aligned.

public interface ICalculator
    int Calculate(int number);

The above C# interface demands extending classes to implement the Calculate method but does not specify any limitations on the parameters or return value. eg can the parameter "number" be a negative number and how high can the number be. C# has no special language support for contracts therefore developers have to have to be cognizant of a classes limitations.

Contracts could consist of:

1. No new exception types/values in a subtype

If the new subtype throws new exceptions the client may not be handling it, which will break the program.

2. Acceptable & unacceptable input types & values / Preconditions cannot be strengthened in a subtype

Conditions BEFORE the method runs (state/parameters) needs to be equal or less strict than the contract (base class / existing usage).

eg if a parameter allows for null, the client will pass nulls to it. If the new implementation is strengthed to not allow nulls, the program will break.

3. Return types & values / Postconditions cannot be weakened in a subtype.

Conditions AFTER the method runs (state/return type) needs to be equal of more strict than the contract (base class / existing usage).

eg if the current implementations guarantee nulls will never be passed back, the client does not handle nulls. If the new implementation is weakened and returns nulls, it might break the program.

4. Invariants of the supertype must be preserved in a subtype.

An invariant is a condition that can be relied upon to be true during the execution of a program.

eg a property being within a specifc range such as a "Day" property being between 1 and 31 to represent day of the month. So whenever you use the class you should be confident that the "Day" value is within its correct range.

5. Side effects

Side effects may lead to unpredictable behavior and should therefore be under contract.

Example Contract

/// <summary>
///  @inv !IsEmpty() implies Top() != null  no null objects are allowed
/// </summary>
public interface IStack<T>
    /// <summary>
    /// @pre t != null
    /// @post !IsEmpty()
    /// @post Top() == t
    /// </summary>
    /// <param name="t"></param>
    void Push(T t);

    /// <summary>
    ///  @pre !IsEmpty()
    ///  @post @return == Top()@pre
    /// <summary>
    /// <returns></returns>
    T Pop();

    /// <summary>
    /// @pre !IsEmpty()
    /// </summary>
    /// <returns></returns>
    T Top();

    bool IsEmpty();

Design by contract considers contracts to be so crucial to software correctness that they should be part of the design process. Design by contract advocates writing the assertions first. Contracts can be written by code comments, enforced by a test suite, or both, even if there is no special language support for contracts. This is akin to modern TDD

Check out these links for more info:

My design and architecture repo