Design by Contract meets .NET
Code Contracts provide a language-agnostic way to express coding assumptions in .NET programs. The contracts take the form of pre-conditions, post-conditions, and object invariants. Contracts act as checked documentation of your external and internal APIs. The contracts are used to improve testing via runtime checking, enable static contract verification, and documentation generation.
Design by Contract
The Design by Contract method is based on the concept of contracts as a way to specify the behavior of code artifacts such as methods. Its roots can be traced back to concepts such as Hoare triples.
The Design by Contract was proposed on the context of the object oriented paradigm, namely the Eiffel language and method.
Among other things, a contract defines the obligations between a method and it’s client, namely:
- The client obligations, defined as require clauses or preconditions, are predicates over the client visible state that must be true when the method starts.
- The methods obligations, named as ensure clauses or postconditions, are predicates that must be true when the method ends.
A contract provides a way to define the meaning of correct implementation. Loosely writing, a method implementation is correct if, for any call that satisfies the requires clauses, the ensures clauses are also satisfied at the end of its execution.
A contract also defines invariants, which are conditions that must hold for all observable states of an object lifetime.
Contracts also interact with class inheritance and method redefinition. Namely, the contract of a redefined method must be a sub-contract of the base method:
- The redefined method must not require more than the base method.
- The redefined method must not ensure less than the base method.
Contracts can be informally described in documentation or can be formally embedded in the code. This last option, adopted by the Eiffel language and method, has several advantages:
- The mere need for defining a code contract forces the programmer to think more carefully about the method specifications, improving the code quality.
- The existence of code contracts allows the automatic generation of code that detects contract violations at runtime.
- Code contracts can also be used by static analysis tools to detect contract violations at build time.
- Finally, code contracts can also be reflected in the automatically generated documentation.
The Eiffel language has specific language mechanisms to represent code contracts, as showed in the following example (note the require and ensure regions before and after the method’s body).
Contracts and .NET
The Spec# project had the goal of introducing the Design by Contract concepts into the C# language. This project included: a set of language extensions to the C# language, a compiler and a static program verifier.
However, the adoption of the Spec# extensions by the C# language is not in the C# team plans, in spite of the great interest manifested by the developer community, and reflected in campaigns such as
In my opinion, the Spec# project had two major drawbacks:
- It required another major change to the C# language syntax.
- It was not directly applicable to other .NET languages.
The Code Contracts project solves this problems by providing a language agnostic way to express contracts in code, as shown in the following code excerpt.
Instead of using language extensions, Code Contracts uses the following mechanisms:
- The contract conditions are expressed via calls to static methods of the CodeContract class. The parameters to these calls are boolean expressions, defined using native language constructs. The CodeContract also contain additional special methods, such as the CodeContract.Result method, that represents the return value.
- The invariant conditions are defined in a special method, annotated with the ContractInvariantMethodAttribute.
- After the compilation step, a binary rewriter (ccrewrite.exe) is used to translate these static methods calls into the real runtime checks.
The code below shows the result of this last rewriting. Namely, notice that the Ensures calls where removed from the beginning of the method and inserted into the end.
I end this post suggesting the download of the current release, available at the Code Contracts site. This release integrates rather well with Visual Studio 2008 (academic license only!). I also suggest the reading of the “Code Contracts User Manual” present in this release.