July 2011

Volume 26 Number 07

Cutting Edge - Code Contracts: Inheritance and the Liskov Principle

By Dino Esposito | July 2011

Dino EspositoJust like real-life contracts, software contracts bind you to additional constraints and cost you something in terms of time. When a contract is standing, you might want to make sure that you don’t break its terms. When it comes to software contracts—including Code Contracts in the Microsoft .NET Framework—nearly every developer will eventually manifest doubts about the computational costs of having contracts around classes. Are contracts appropriate for your software, regardless of the type of build? Or are contracts instead mostly a debugging aid that should be stripped off retail code?

Eiffel, the first language to introduce software contracts, has native language keywords to define preconditions, postconditions and invariants. In Eiffel, therefore, contracts are part of the language. If used in the source code of a class, then contracts become an integral part of the code.

In .NET, though, contracts are part of the framework and don’t belong to supported languages. This means that runtime checking can be enabled or disabled at will. In particular, in .NET you’re allowed to decide about contracts on a per-build configuration basis. In Java, things are nearly the same. You use an external framework and either add contract code to the sources to be compiled or ask tools around the framework to modify the bytecode accordingly.

In this article, I’ll discuss a few scenarios where Code Contracts prove particularly helpful in driving you toward a higher quality of overall software design.

What Code Contracts Are For

An evergreen best practice of software developers is writing methods that carefully check any input parameters they receive. If the input parameter doesn’t match the expectations of the method, then an exception is thrown. This is known as the if-then-throw pattern. With precondition contracts, this same code looks nicer and more compact. More interestingly, it also reads better, because a precondition lets you clearly state just what’s required instead of testing against what isn’t desirable. So, at first sight, software contracts simply look like a nicer-to-write approach to prevent exceptions in class methods. Well, there’s a lot more to it than just that.

The simple fact that you think of contracts for each and every method indicates that you’re now thinking more about the role of those methods. In the end, design gets terser and terser. And contracts also represent a valuable form of documentation, especially for refactoring purposes.

Code Contracts, however, aren’t limited to preconditions, even though preconditions are the easiest part of software contracts to pick up. The combination of preconditions, postconditions and invariants—and the extensive application of them throughout your code—gives you a decisive advantage and really leads to some higher-quality code.

Assertions vs. Code Contracts vs. Tests

Code Contracts aren’t entirely like assertions and other debug instruments. While contracts can help you track down bugs, they don’t replace either a good debugger or a well-done set of unit tests. Like assertions, Code Contracts indicate a condition that must be verified at a certain point during the execution of a program.

An assertion that fails is a symptom that something is wrong somewhere. An assertion, however, can’t tell you why it failed and where the problem originated. A Code Contract that fails, on the other hand, tells you a lot more. It shares details about the kind of failure. So, for example, you can learn whether the exception was raised because a given method received an unacceptable value, failed in the calculation of the expected return value or holds an invalid state. Whereas an assertion tells you only about a detected bad symptom, a Code Contract can show invaluable information on how the method should be used. This information may ultimately help you understand what has to be fixed in order to stop violating a given assertion.

How do software contracts relate to unit testing? Obviously, one doesn’t exclude the other and the two features are sort of orthogonal. A test harness is an external program that works by applying a fixed input to selected classes and methods to see how they behave. Contracts are a way for the classes to yell out when something is wrong. In order to test contracts, however, you must be running the code.

Unit tests are a great tool to catch regression after a deep refactoring process. Contracts are perhaps more informative than tests to document the expected behavior of methods. To get design value out of testing, you must be practicing test-driven development (TDD). Contracts are probably a simpler tool than TDD to document and design methods.

Contracts add extra information to your code and leave it up to you to decide whether this information should make it to the deployed binaries. Unit testing involves an external project that can estimate how the code is doing. Whether you compile contract information or not, having clear contract information in advance helps immensely as a documentation and design aid.

Code Contracts and Input Data

Contracts refer to conditions that always hold true in the normal execution flow of a program. This seems to suggest that the ideal place where you might want to use contracts is in internal libraries that are only subject to input strictly controlled by the developer. Classes that are directly exposed to user input aren’t necessarily a good place for contracts. If you set preconditions on unfiltered input data, the contract may fail and throw an exception. But is this really what you want? Most of the time, you want to degrade gracefully or return a polite message to the user. You don’t want an exception and you don’t want to throw and then trap an exception just to recover gracefully.

In .NET, Code Contracts belong to libraries and may be a good complement to (and, in some cases, a replacement for) data annotations. Data annotations do a great job in relation to the UI because in Silverlight and ASP.NET you have components that understand those annotations and adjust the code or the HTML output. On the domain layer, though, you often need more than just attributes, and Code Contracts are an ideal replacement. I’m not necessarily stating that you can’t get the same capabilities with attributes that you can with Code Contracts. I find, however, that in terms of readability and expressivity, the results are better with Code Contracts than attributes. (By the way, this is precisely why the Code Contracts team prefers plain code over attributes.)

Inherited Contracts

Software contracts are inheritable in nearly any platform that supports them, and the .NET Framework is no exception. When you derive a new class from an existing one, the derived class picks up the behavior, context and contracts of the parent. That seems to be the natural course of things. Inheritance of contracts doesn’t pose any issue for invariants and postconditions. It’s a bit problematic for preconditions, though. Let’s tackle invariants and consider the code in Figure 1.

Figure 1 Inheriting Invariants

public class Rectangle
{
  public virtual Int32 Width { get; set; }
  public virtual Int32 Height { get; set; }
  [ContractInvariantMethod]
  private void ObjectInvariant()
  {
    Contract.Invariant(Width > 0);
    Contract.Invariant(Height > 0);
  }
}
public class Square : Rectangle
{
  public Square()
  {
  }
  public Square(Int32 size)
  {
    Width = size;
    Height = size;
  }
  [ContractInvariantMethod]
  private void ObjectInvariant()
  {
    Contract.Invariant(Width == Height);
  }
  ...
}

The base class Rectangle has two invariants: width and height are greater than zero. The derived class Square adds another invariant condition: width and height must match. Even from a logical perspective, this makes sense. A square is like a rectangle except that it has an additional constraint: width and height must always be the same.

For postconditions, things mostly work in the same manner. A derived class that overrides a method and adds more postconditions just augments the capabilities of the base class and acts like a special case of the parent class that does all the parent does and more.

What about preconditions, then? That’s exactly why summing up contracts across a class hierarchy is a delicate operation. Logically speaking, a class method is the same as a math function. Both get some input values and produce some output. In mathematics, the range of values produced by a function is known as the codomain; the domain is the range of possible input values. By adding invariants and postconditions to a derived class method, you just increase the size of the method’s codomain. But by adding preconditions, you restrict the method’s domain. Is this something you should really be worried about? Read on.

The Liskov Principle

SOLID is a popular acronym that results from the initials of five key principles of software design including Single responsibility, Open/Closed, Interface segregation and Dependency inversion. The L in SOLID stands for the Liskov substitution principle. You can learn a lot more about the Liskov principle at bit.ly/lKXCxF.

In a nutshell, the Liskov principle states that it should always be safe to use a subclass in any place where the parent class is expected. As emphatic as it may sound, this is not something that we get out of the box with plain object orientation. No compiler of any object-oriented language can do the magic of ensuring that the principle always holds.

It’s a precise developer’s responsibility to ensure that it’s safe to use any derived class in places where the parent class is expected. Notice I said “safe.” Plain object orientation makes it possible to use any derived classes in places where the parent class is expected. “Possible” isn’t the same as “safe.” To fulfill the Liskov principle, you need to adhere to a simple rule: The domain of a method can’t be shrunk in a subclass.

Code Contracts and the Liskov Principle

Aside from the formal and abstract definition, the Liskov principle has a lot to do with software contracts and can be easily rephrased in terms of a specific technology such as .NET Code Contracts. The key point is that a derived class can’t just add preconditions. In doing so, it will restrict the range of possible values being accepted for a method, possibly creating runtime failures.

It’s important to note that violating the principle doesn’t necessarily result in a runtime exception or misbehavior. However, it’s a sign that a possible counterexample breaks your code. In other words, effects of violation may ripple across the entire codebase and show nefarious symptoms in apparently unrelated areas. It makes the entire codebase harder to maintain and evolve—a deadly sin these days. Imagine you have the code in Figure 2.

Figure 2 Illustrating the Liskov Principle

public class Rectangle
{
  public Int32 Width { get; private set; }
  public Int32 Height { get; private set; }
  public virtual void SetSize(Int32 width, Int32 height)
  {
    Width = width;
    Height = height;
  }
}
public class Square : Rectangle
{
  public override void SetSize(Int32 width, Int32 height)
  {
    Contract.Requires<ArgumentException>(width == height);
    base.SetSize(width, width);
  }
}

The class Square inherits from Rectangle and just adds one precondition. At this point, the following code (which represents a possible counterexample) will fail:

private static void Transform(Rectangle rect)
  {
    // Height becomes twice the width
    rect.SetSize(rect.Width, 2*rect.Width);
  }

The method Transform was originally written to deal with instances of the Rectangle class, and it does its job quite well. Suppose that one day you extend the system and start passing instances of Square to the same (untouched) code, as shown here:

var square = new Square();
square.SetSize(20, 20);
Transform(square);

 Depending on the relationship between Square and Rectangle, the Transform method may start failing without an apparent explanation.

Worse yet, you may easily spot how to fix the issue, but because of the hierarchy of classes, it may not be something you want to take lightly. So you end up fixing the bug with a workaround, as shown here:

private static void Transform(Rectangle rect)
{
  // Height becomes twice the width
  if (rect is Square)
  {
    // ...
    return;
  }
  rect.SetSize(rect.Width, 2*rect.Width);
}

But regardless of your effort, the notorious ball of mud has just started to grow bigger. The nice thing about .NET and the C# compiler is that if you use Code Contracts to express preconditions, you get a warning from the compiler if you’re violating the Liskov principle (see Figure 3).

The Warning You Get When You’re Violating the Liskov Principle

Figure 3 The Warning You Get When You’re Violating the Liskov Principle

The Least-Understood and Least-Applied SOLID Principle

Having taught a .NET design class for a couple of years now, I think I can safely say that of the SOLID principles, the Liskov principle is by far the least understood and applied. Quite often, a weird behavior detected in a software system can be tracked down to a violation of the Liskov principle. Nicely enough, Code Contracts can help significantly in this area, if only you take a careful look at compiler warnings.


Dino Esposito is the author of “Programming Microsoft ASP.NET 4” (Microsoft Press, 2011) and coauthor of “Microsoft .NET: Architecting Applications for the Enterprise” (Microsoft Press, 2008). Based in Italy, Esposito is a frequent speaker at industry events worldwide. You can follow him on Twitter at twitter.com/despos.

Thanks to the following technical expert for reviewing this article: Manuel Fahndrich