Chapter 15. Letting your code speak more clearly with Code Contracts

This chapter covers

  • The objectives of Code Contracts
  • Writing contracts in your code
  • Binary rewriting
  • Static checking
  • Contract documentation
  • Applying contracts

This book is about C#, the language. I haven’t attempted to cover the whole of the .NET framework or even just the Base Class Library (BCL). Apart from when we were looking at different LINQ providers in chapter 12, I’ve been rigidly focused on explaining the features introduced in each version of C#. This chapter is somewhat different. It’s not about a new ability of the language itself, but a combination of tools and types (collectively called Code Contracts) that can radically change your code’s appearance and how much information it conveys. If this were a book about the English language, this would be a chapter on poetry. Even though poems use the same words as prose, they look and feel different. You need to read them in a particular way to understand what they’re trying to express, but they can convey a lot of meaning in a powerful way.

Now I’m aware that this all sounds melodramatic, and the difference made by Code Contracts isn’t quite as striking as reading Shakespeare, but it’s pretty special nonetheless. I hope that contracts take off to such an extent that within a few years, any book that attempts to convey idiomatic C# without demonstrating them would be seen as hideously outdated. Obviously I don’t want this book to be viewed in that light, so I’ve stretched my objective of being language focused to include this chapter.

Contracts allow developers to express requirements and promises between APIs. Guarantees that have previously been given in documentation can now be stated once in code and automatically checked at execution time. Of course you’ve always been able to write assertions and argument validation in the past, but Code Contracts makes the whole process a lot smoother, with features such as contract inheritance and automatic documentation generation. Additionally, if you’re using Visual Studio Premium or Ultimate, the contracts can be used to check your code for correctness at compile time.

Although this isn’t part of C# 4 itself, it has the same ubiquitous nature as language constructs. Whereas specific APIs for web services, database access, UI development, and so on are only relevant in certain situations, contracts are almost universally useful. When you treat the contracts as part of the task of designing a type, you’ll find you not only communicate your intentions more clearly with other developers, but you understand your code’s boundaries better yourself.

One of the consequences of this being a nonspecific technology is that it isn’t suited to full business-related examples. As such, most of the code samples in this chapter are short and don’t do anything useful in themselves. You may find it helpful to keep in mind a bit of code that you’re working on at the moment. Take a look at both the code and documentation for a method, and ask yourself what it’s trying to say. What does it need in order to do its job correctly? What will the results of that job be? At a larger level, what can you always say about the state of your object? Combining my examples of how to express contracts with your own real-world code may make the chapter more meaningful for you.

We’re going to start off by looking at how contracts have been expressed relatively informally before now, and then see how Code Contracts treats the same ideas. Once we have the hang of what contracts are for, we’ll look at what the tools can do to enforce them both at compile time and execution time. Finally, I’ll attempt to give some practical advice. There are lots of different ways of using contracts, and the tools provide a huge range of options. You’ll have to think about what’s right for your particular context, but I hope I’ll get you thinking along the right lines.

15.1. Life before Code Contracts

The idea of contracts isn’t new. Bertrand Meyer made it a key part of the design of the Eiffel programming language in the 1980s, and it’s been gradually becoming more mainstream ever since. A lot of computer science research has gone into formal specification and verification, which allows a program to be checked for correctness at compile time, but that isn’t the only benefit of contracts.

At the heart of programming by contract is the idea of separating the requirements and guarantees of an API from the implementation. It’s no coincidence that this sounds like the use of interfaces, but contracts allow a much richer expression of behavior. You may be thinking that there’s nothing new about the idea of specifying what a method will do, and what it requires of its inputs. We do that all the time with documentation. There’s nothing new about the idea of checking this at execution time, either. Of course, sometimes the two might get slightly out of sync, but we usually seem to get by.

Suppose we were to write a method that counted the number of whitespace characters in a given string. The following listing shows one possible implementation.

Listing 15.1. Simple method with argument validation and documentation
/// <summary>Counts the number of whitespace characters
/// in <paramref name="text"/>.</summary>
/// <param name="text">String to examine. Must not be null.</param>
/// <exception cref="ArgumentNullException">
/// <paramref name="text"/> is null.</exception>
/// <returns>The number of whitespace characters.</returns>
static int CountWhitespace(string text)
{
if (text == null)
{
throw new ArgumentNullException("text");
}
return text.Count(char.IsWhiteSpace);
}

Listing 15.1 has more XML documentation than I usually provide, I’ll admit. I rarely bother documenting exceptions that are obvious from the text: in this case we’ve already stated that text can’t be null, so why add the extra fluff? Likewise I’m sometimes sloppy when it comes to providing proper parameter references and the like. I’m somewhat pickier for public APIs, but not to the point of perfectionism. I strongly suspect I’m not alone in this. If you pay as much attention to the documentation of your methods as the implementation, my guess is that you’re in a tiny minority.

We’re being pretty rigorous in the implementation, validating that the parameter isn’t null. The fact that it’s taking up four out of the five lines is unfortunate, but avoidable. I’ve found it handy to have a generic extension method with a reference type constraint that lets me write validation like this:

text.ThrowIfNull("text");

It’s annoying to have to restate the name of the parameter (and I usually have an overload allowing me to omit it when I don’t care) but at least it’s compact. Some people object to this as an abuse of extension methods, but I find it useful. In particular it’s more compact than writing something like ExceptionUtils.ThrowIfNull(text, "text"): the name of the class here is pure cruft; it doesn’t help us understand the code at all. Arguably in this case you could just let Enumerable.Count throw ArgumentNullException, but then the reported parameter name would be source instead of text, which isn’t ideal. It’s also generally preferable to explicitly perform validation before doing anything else: it makes it a lot easier to guarantee that calling a method with invalid arguments won’t have any side effects beyond the exception being thrown.

An alternative to this would be to use Debug.Assert(text != null), which performs the same checking for debug builds but won’t (by default) catch bad arguments in a release build. Finally, you could use exactly the same code, but put it all on one line, possibly omitting the braces. Personally I don’t favor that style, but it’s an alternative to consider.

Even with all this bulk around what’s effectively a single-line implementation, we haven’t said all we could. We know that the return value will always be greater than or equal to 0. (You can’t create strings with lengths greater than int.MaxValue.) We could communicate that by making the return value uint instead, but unsigned types aren’t used particularly commonly in .NET, partly because they’re not CLS-compliant. It’s reasonably obvious to a human that this will be the case, but not to a machine. It’s also tricky to verify that claim at execution time in the general case, unless you rigorously stick to a single exit point per method, which I find detrimental to readability in many situations.

Why would a machine care whether the return value was nonnegative? Well, suppose we then wanted to feed that into another method for some reason, and that method required the argument to be nonnegative. Wouldn’t it be nice if something could check that we met that requirement—and also check at execution time that the first method really did return a nonnegative value? Enter Code Contracts.

15.2. Introducing Code Contracts

Code Contracts has its roots in a research language developed by Microsoft called Spec# (see http://mng.bz/4147). Like CΩ (the research language that spawned LINQ), this is a C#-like language with a twist. In this case, the main twist is contracts, which are expressed in a declarative manner. For example, in Spec#, expressing the contract that a parameter has to be non-null is a simple matter of changing the declared type of the parameter:

static int CountWhitespace(string! text)
{
return text.Count(char.IsWhiteSpace);
}

Spec# features compile-time support for non-nullable reference types as well as a sophisticated program verifier.

Code Contracts attempts to cover the same sort of ground, but purely with a library and tools. This approach has the advantage of giving all the benefits to all languages immediately, but doesn’t yield quite as concise code. Contracts are expressed at a per-type and a per-member level as calls to methods in the System.Diagnostics.Contracts.Contract class. Unless I specify otherwise, every contract-related method in this section is in the Contract class.

A tool called ccrewrite—also known as the binary rewriter—then executes as part of the build[1] to make sure that the contracts are enforced according to your project settings. A closely related tool is ccrefgen, which generates contract reference assemblies to be distributed alongside the implementation assemblies, giving contract information to clients even if the contract checks have been removed from the implementation. Another tool called cccheck—also known as the static checker—is available if you’re using Visual Studio 2010 Premium or Ultimate edition. The aim of the checker is to prove that your code will satisfy your contracts at compile time, rather than just checking what’s actually happening at execution time. Finally, you can probably guess what ccdocgen is for: it generates XML documentation for the contracts specified in the code.

1 It’s only part of the build if you’re using msbuild, either directly or from Visual Studio. If you’re running the C# compiler manually, you’ll need to run ccrewrite too. The same is true for the other tools.

The Code Contract tools aren’t included in Visual Studio 2010 or .NET 4, but the core types are exposed in mscorlib. You need to download the tools from the Code Contracts DevLabs page (http://mng.bz/CN2k); after installation your Visual Studio project properties page should have a Code Contracts tab, as shown[2] in figure 15.1. The contracts can be broadly divided into five main categories. We’ll look at each category briefly so we know what’s available, and then see what the tools are capable of once we’ve defined our contracts.

2 This screenshot was taken using Visual Studio 2010 Premium; static checking isn’t supported in Visual Studio 2010 Professional, so that part of the properties page may be blank. Additionally, the properties page is evolving with the tools—by the time you read this, it may have changed appearance and functionality.

Figure 15.1. Code Contracts project property page in Visual Studio 2010

15.2.1. Preconditions

Preconditions make requirements of the caller of a method rather than expressing anything about the behavior of the method itself in normal conditions. We all know that our code works perfectly but no one else’s can be trusted, so preconditions are the most common form of contract-like code in existing programs. That’s exactly what we have in our whitespace-counting sample: we require that the text parameter be non-null. Preconditions are expressed with the Requires method. There are four forms of this—each takes a condition, but there’s also an optional message and an exception type can be expressed as a type argument.

As we’re putting a burden on the caller, the condition has to be expressed in terms that the caller is in charge of or can at least check. Code Contracts will warn you if a member’s precondition depends on a piece of state with less visibility than the member—it wouldn’t be fair to the caller.[3]

3 You can decorate a private field with the [ContractPublicPropertyName] attribute. This lets you refer to the private field within preconditions, knowing that the caller can get at the same information with a property.

If you don’t specify a type argument, a contract failure will throw a ContractException—if none of the contract failure handlers involved terminate the process first. The execution-time behavior of contracts is complicated, but we’ll look at it in the next section. For now, we’re just seeing what the contracts look like. Here’s our whitespace counter with a simple precondition:

static int CountWhitespace(string text)
{
Contract.Requires(text != null);
return text.Count(char.IsWhiteSpace);
}

If we wanted to still throw ArgumentNullException, we could use the generic form of Requires, which specifies which exception to throw:

static int CountWhitespace(string text)
{
Contract.Requires<ArgumentNullException>(text != null, "text");
return text.Count(char.IsWhiteSpace);
}

This time we specify the message explicitly, because we want the exception thrown to have the right value for its ParamName property.

For other contract types, you don’t need to make the decision between the default behavior and a specific exception type, because they involve failures in your code rather than the caller’s. Let’s move on to the opposite of preconditions: postconditions.

15.2.2. Postconditions

Whereas preconditions express constraints on the input to a method (potentially including the original state of the target object), postconditions express constraints on the output of a method: its return value, any out or ref parameter values, and any mutated state (whether in the target object or one of the parameters). Postconditions are expressed with the Ensures method. For example, we can easily express that our whitespace counter will never return a negative value,[4] as shown in the following listing.

4 We could also add a postcondition for the upper bound: the method will never return a value larger than the length of the text that’s passed in. I’m going to keep it simple here, though.

Listing 15.2. Expressing a simple postcondition for a return value
static int CountWhitespace(string text)
{
Contract.Requires(text != null, "text");
Contract.Ensures(Contract.Result<int>() >= 0);
return text.Count(char.IsWhiteSpace);
}

You may be surprised to see that the postcondition comes before the actual implementation. On the face of it, that makes no sense—it can’t possibly check the return value before it’s calculated. This is where there’s an important difference between Code Contracts and any manual assertions we could’ve implemented before. Previously, the implementation code and the checks were intermingled—there was no difference between them, essentially. Code Contracts are all about expressing the checks, not executing them. The binary rewriter takes care of actually validating the contract at execution time if necessary, or removing the checks entirely otherwise.

All preconditions and postconditions are expressed before the main implementation in Code Contracts. The tools assume that anything that comes after the last reference to Contract (apart from calls to Assert and Assume, which we’ll meet in a minute) is part of the implementation, but anything up to that point is purely contractual and has no impact on the real work of the method. If you mistakenly put a postcondition at the end of the method, Code Contracts will complain of a “malformed contract.”

Normally to express a postcondition on a return value, you’d set the candidate return value in a local variable, test that its value was appropriate, and then return it. Obviously we can’t do that when the contract is expressed before the implementation, so the Result<T> method acts as a sort of placeholder: when the tools see a call to it, they know it means “the return value when we really get there.”

Two similar methods exist for situations where you want to refer to state that changes during the course of execution. The OldValue method refers to the original state, and ValueAtReturn refers to the final state. The rewritten code will capture any original state it needs to after the preconditions are checked. Listing 15.3 shows an example of using all three of these methods in a single contract. The implementation is buggy, but the postcondition protects the caller by alerting them to the problem.

Listing 15.3. A complicated postcondition involving a return value, old and new state

The idea behind the method in listing 15.3 is for it to act like int.TryParse, but instead of taking an out parameter to receive the result, it takes a ref parameter. If parsing fails, the value should stay as it was before—this makes it easy to use a default value. In other words, either our return value should be true (successful parse) or the value should be the same at the end as it was at the start. Unfortunately, our implementation doesn’t obey this properly—it uses the parameter as an argument to int.TryParse, which will overwrite the value with 0 if parsing fails.[5] The postcondition will spot this and blow up appropriately rather than letting the caller continue assuming that the implementation was correct.

5 The fix to this bug is just to use a local variable as the argument to int.TryParse, and then conditionally copy the value into the ref parameter. The corrected code is in the downloadable source.

One final feature of postconditions is exception handling. Any contract expressed using Ensures is only relevant when the method completes normally. You can specify any postconditions for exceptional situations using EnsuresOnThrow<T>, where T is an exception type. This allows you to have different postconditions for different scenarios, although this isn’t typically needed.

15.2.3. Invariants

So far we haven’t actually used any state in our tests, although we certainly could have—it’s entirely reasonable to depend on the initial state of an object in a precondition, and a method that mutates an object may want to express the intended result as a postcondition.

Invariants are slightly different: they’re contracts about the state of the object which should apply at all times that the state is visible. In other words, it’s okay to change an invariant while a public method in the class is running, but at the end of the method the invariant should be satisfied again. In Code Contracts, invariants are expressed through an extra method decorated with the ContractInvariantMethod attribute. The method is conventionally named ObjectInvariant, but it doesn’t have to be. Inside the method, you call Invariant to check the invariants. When invariants are enabled, they are run at the end of every public method.[6]

6 Finalizers and implementations of IDisposable.Dispose don’t check the invariant at the end. It’s expected that the object may be unusable after disposal.

Despite the name, invariants aren’t always about a value remaining the same. They’re about a fixed condition always holding. For example, you might have a string variable which is modified over the lifetime of an object, but which should never be null. You could express that fact everywhere that the field was modified, but it’d be easy to make a mistake. An invariant allows you to apply the check automatically at predictable places.

As another example, suppose we were writing a card game. Cards can move between the deck, a player’s hand, and the discard pile—but cards are never duplicated or lost. We can express this reasonably cheaply as an object invariant by counting the cards in each location. Here’s the skeleton of a possible CardGame class, including its invariant:

public sealed class CardGame
{
private readonly Stack<Card> deck =
new Stack<Card>(Card.CreateFullDeck());
private readonly Stack<Card> discardPile = new Stack<Card>();
private readonly List<Player> players = new List<Player>();

public void DealCard(Player player) { ... }

[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(deck.Count + discardPile.Count +
players.Sum(p => p.CardCount) == Card.FullDeckSize);
}
}

For such a short piece of code, there’s a lot to talk about. The obvious point is that the invariant method is a void, parameterless method decorated with the required attribute to make it an object invariant. It’s also private: even in nonsealed classes, the invariant method must be private. Derived classes need to be able to call the invariant implicitly, but the binary rewriter takes care of that for you by turning it into a protected method with an unspeakable name.

It’s worth noting that the invariant I’ve expressed isn’t foolproof by any means. We’re only checking how many cards there are, not that they’re all different. A method to deal a card could easily break a more strict invariant but pass this one. But by making the invariant cheap to execute, we can keep it enabled in more situations without worrying about losing too much performance.

All the work is done in the evaluation of the argument to Invariant. An invariant method can only contain calls to Invariant, with no loops, local variables, and so on. This is important for the sake of the static checker, which tries to understand what your invariants really mean in order to prove that they’re maintained. If it gets really difficult to express an invariant inline in a single expression, you can always create another method or property to call, but this will leave the static checker with less chance of helping you.

There are two methods to help express contracts (including preconditions and postconditions) more simply: ForAll and Exists, which take predicates to check for a range of items. For example, if you wanted to express an invariant that a collection didn’t contain any null elements, you could use either of the following equivalent contracts:

Contract.Invariant(Contract.ForAll(collection, item => item != null));
Contract.Invariant(!Contract.Exists(collection, item => item == null));

Sometimes, there are conditions that you want to check during the execution of the method. These aren’t contracts in the same sense as preconditions, postconditions, and invariants, but they’re still validating the logic of the method.

15.2.4. Assertions and assumptions

So far we’ve been performing sanity checking before or after executing the useful work of a method. That’s fine in many cases, particularly for short methods, but sometimes it’s nice to be able to put a stake in the ground about what’s going on halfway through a method.[7] Code Contracts provides two methods for this: Assert and Assume. If you’re not using the static checker, you don’t need to know the difference between them, and they both act in a similar way to the familiar Debug.Assert method, checking that a condition is true at execution time, assuming assertions are enabled.

7 This is in no way meant to discourage you from trying to write short methods—short methods with preconditions and postconditions can sometimes remove the need for midmethod contracts. Sometimes it’s just too hard, though.

The static checker treats the two somewhat differently. It tries to prove that an assertion is correct, but makes no such attempt for an assumption: it believes that you know what you’re claiming. In both cases, it’ll add the condition to its set of known facts from that point onward. If you can use Assert instead of Assume, it’s a more powerful method—but Assume is useful if you want to effectively let the static checker know something it can’t prove. Listing 15.4 shows an example of this, providing a method to simulate rolling a pair of dice.

Listing 15.4. Making assumptions and assertions when rolling dice

Listing 15.4 provides a method that can roll a pair of pseudorandom six-sided dice, either based on a new instance of Random with a time-based seed or an existing instance. First we express a postcondition which states that the outcome of rolling the two dice will be between 2 and 12 inclusive. By the end of the method, the static checker should be able to prove that this is the case.

After we’ve possibly created a new instance of Random, we know that the rng variable won’t be null, so we’re safe to call methods on it. We’re so sure of this that we assert it—we think the static checker will be able to prove it . Usually assertions would be more complicated, of course: we’d be asking the checker to prove something that wasn’t obvious, both for our own peace of mind and for the benefit of anyone reading the code later.

Now that we definitely have a reference to a random-number generator, we can roll the dice. Let’s assume the static checker doesn’t know what Random.Next does,[8] so we tell it what it can assume about the output . Based on those assumptions, the static checker will try to check our postconditions. Note that each of the conditions we’ve specified (for each of the dice rolls and for our postcondition) is split into two parts: one for the minimum value, and one for the maximum. The static checker is able to understand individual contracts more easily than compound ones using the && operator. Not only is it able to prove more results this way, but the error messages are clearer too, as it can point out exactly which condition may be violated.

8 In fact, Random.Next now has contracts applied to it, so we could’ve used Assert or just let the checker work it out. Just pretend that it doesn’t have any contracts for the sake of the example—a lot of existing code doesn’t!

15.2.5. Legacy contracts

The final type of contract is really another kind of precondition—and we’ve already seen an example of it, way back before we started using the contracts library. Legacy contracts are the preconditions we expressed with if/throw statements in our original code. Legacy contracts have to be expressed simply, using just conditions with throw statements. There can’t be any assignments or any other impure code.

 

Purity

You can call other code from all contracts, but only if it’s pure. This means it can’t have any side effects. You can use the [Pure] attribute to mark your own methods as being pure, and you can call existing pure methods defined on other types. The Code Contracts documentation lists the framework methods that are assumed to be pure—most notably anything in System.String, and the Predicate<T> and Comparison<T> delegates. The contract reference assemblies shipped with Code Contracts also decorate other aspects of the framework, such as the Enumerable.Sum method we called in the previous section. Operators and property getters are also assumed to be pure.

 

As I mentioned when we discussed postconditions, the Code Contracts tools assume that anything after the last reference to Contract is part of the functional part of the method implementation. Our original code didn’t have any code calling Contract at all, so we need to give the tools a clue using EndContractBlock, as shown in the following listing.

Listing 15.5. Signalling the end of a contract block explicitly

Just to be clear, the EndContractBlock method does absolutely nothing at execution time. It’s solely there for the benefit of the binary rewriter, which actually removes the call in the rewritten code. An alternative strategy is to replace legacy contracts with the new ones. If you express another new style contract such as a postcondition after the legacy contract but before the main body of the code, the rewriter knows what to do automatically: you don’t need EndContractBlock in that situation. This has the additional benefit of expressing the postcondition, which has to be a good thing. But I’d personally go the whole hog and convert the preconditions to the new style of contracts—it makes the code more consistent, as well as making the rewriter include a more useful error message if the contract is violated. There’s not a lot of advantage to maintaining the legacy contracts—although they could make it slightly easier to have one build targeting a recent framework and using Code Contracts, and another build targeting (say) .NET 2.0 and using just legacy contracts. At that point, you’d only need to write an EndContractBlock method in your own Contract class, and you’d have compatibility. This is a fairly extreme case—it’d usually just be better to convert the code.

It’s worth bearing in mind that even just using EndContractBlock could be considered a breaking change to existing code. Depending on your exact settings, you may end up with a different exception being thrown by the contract checker, or the precondition being removed entirely, leaving your method to blithely execute its main code with potentially invalid parameters.

If the tools detect that you’re using code that isn’t part of a contract from within the contract section, it’ll report an error. There are cases that’ll fool the tools, but most problems will be caught this way.

Now that we’ve seen the basics of what we can do with contracts, we really need to look at how the tools involved use them. We’ll start off with the binary rewriter.

15.3. Rewriting binaries with ccrewrite and ccrefgen

In the history of .NET, there have been many advances that have required two or more pieces of the ecosystem to both improve at the same time. Even features that don’t require any explicit library or runtime support (such as object initializers and anonymous types) have typically been designed to fit into a grander plan. In the case of Code Contracts, the library and the supporting tools really are critical to each other. You can express some contracts in code but then ignore the tools. The preconditions will be checked (so long as you define the CONTRACTS_FULL or CONTRACTS_PRECONDITIONS preprocessor symbol); postconditions will generate an assertion telling you to use the rewriter; invariants simply won’t be called. Likewise you can use the binary rewriter without expressing any contracts—but don’t expect it to do anything useful.

We’ll look at documentation and static checking later, but the rewriter is at the core of Code Contracts. Let’s see what it can do.

15.3.1. Simple rewriting

Just as the name suggests, the binary rewriter takes the assembly you’ve just built and rewrites parts of it. Usually it replaces the original assembly, but you can ask it to create a new one in another directory instead. Some of the operations are pretty much what you’d expect, but there are sophisticated features too. Let’s start with the obvious ones. For each method, the rewriter will rewrite it so that it follows this sequence of events:

  • Preconditions are checked.
  • Initial state is captured for OldValue method calls.
  • The functional part of the code executes (including any assertions and assumptions being checked; they aren’t moved around by the binary rewriter).
  • Postconditions are checked.
  • Invariants are checked on public methods.

Unless you’ve already specified a message in the contract, the rewriter examines your source code and rewrites the contract to use the actual code for the message. You have to build a PDB file for it to extract the source, but the default settings for Visual Studio work fine for both debug and release builds. The target of the contract call is also changed—instead of using the version of Contract in mscorlib, a new type is created in the rewritten assembly called __ContractsRuntime. This contains everything required at execution time, and also has a nested type called ContractException, which is the exception type used by default for failed contracts that didn’t have another one specified explicitly.

Various options may remove some of these checks; for instance, you may only want to check preconditions for a release build, or only check contracts for public methods. You can use the Perform Runtime Contract Checking and Only Public Surface Contracts options in the project property page to control which contracts are included in the rewritten file.

The rewriter’s behavior can be tweaked in a number of ways, and I’m not going to delve into every available switch, but I’ll cover the most important options. If you can imagine some form of flexibility that might be useful, chances are ccrewrite supports it. This should reinforce the idea that contracts aren’t normal code. The C# compiler doesn’t know anything special about contracts—it thinks they’re normal code—but the rewriter can radically change how your code behaves.

If you look inside the rewritten code, you’ll see that there’s slightly more to it even in the simplest case. Just in case you use a method or property with a contract as part of evaluating another contract, there’s a recursion guard to stop the contract from blowing up the stack. Combining all of this together, our simplest contract method is rewritten as the following.

Listing 15.6. A simple contract after binary rewriting
private static int CountWhitespace(string text)
{
if (__ContractsRuntime.insideContractEvaluation <= 4)
{
try
{
__ContractsRuntime.insideContractEvaluation++;
__ContractsRuntime.Requires(text != null, null,
"text != null");
}
finally
{
__ContractsRuntime.insideContractEvaluation--;
}
}
return text.Count(char.IsWhiteSpace);
}

Fortunately you’ll rarely need to dive into the details of this, but it can make for some interesting reading—particularly when other options are involved. What appears to be a simple method can become quite complex. Any concerns about the impact on performance should be measured rather than guessed, but it’s worth considering that this extra complexity may reduce the CLR’s ability to inline code.

Another way to introduce complexity is to bring inheritance into the picture. That’s true in general, but Code Contracts brings an extra (welcome) twist.

15.3.2. Contract inheritance

It’s hard to say what I like best about Code Contracts, but contract inheritance is certainly one of the neatest features. It can be summed up in two rules:

  • When you override a method (or implement an interface method), you inherit its contracts.
  • You can’t add extra preconditions to inherited ones, but you can make invariants and postconditions stronger.

Let’s get the second rule out of the way first. It’s really about Liskov’s Substitution Principle (see http://mng.bz/sb2w): if a caller only knows that it’s using an interface, and its call meets all the preconditions in the interface, it would be unfair to claim that it violated a contract that you happen to want on your implementation. But you can guarantee that your implementation goes above and beyond the call of duty when it comes to postconditions and invariants.

Bearing that in mind, how does the first rule work? Essentially the rewriter inserts all the inherited preconditions and postconditions into the methods as it goes, and makes any invariant methods call the base invariant method if there is one. The following listing shows an example of this, as well as displaying the order in which the contracts are tested.

Listing 15.7. Contract inheritance with concrete classes

The Report method is used to simulate a condition that’s always satisfied, and also give an indication of what’s going on without having to decompile the code. The code does nothing other than check the fake condition. We have a virtual method declared in Base and overridden in Derived ; both have postconditions but only the base declaration is allowed to specify preconditions. In the downloadable source code version, there are also invariants in both classes to demonstrate inheritance there, too. The output of listing 15.7 makes it clear that even though the override in Derived doesn’t call base.VirtualMethod(), the contracts are still enforced:

Base precondition
Derived postcondition
Base postcondition

In the case of invariants, the base invariant is called before the derived one.

 

Breaking Invariants Sneakily

Invariants are only applied to public methods... and the rewriter only applies the invariant of the class that it knows about. If a public method in a base class calls a protected virtual method in a derived class, that method may break the derived class’s invariant without it being checked. There’s an example in the full source code, and there are other ways of observing an object while its invariants are broken unless you’re careful.

The lesson is to not assume that invariants are bulletproof. You should understand when they’re expected to hold, and if you do expose the object in a broken state (such as via a callback), you should document that clearly.

 

That’s all well and good, I hear you say, but what about abstract methods and interfaces? How can we express the contracts for methods we’re not implementing? Good question. I’m personally somewhat wary of class inheritance—I think it’s easy to abuse and hard to design well. Interfaces, though, are great—it’d be a pity if we couldn’t express contracts on them.

Fortunately, we can. We just need to create a new abstract class to implement the interface or derive from the abstract class, purely for the sake of expressing contracts. This is called the contract class. We then decorate the interface or abstract class with a [ContractClass(...)] attribute, and also add a[ContractClassFor(...)] attribute to the contract class. The contract class implements the methods just by a series of contract calls, and the contracts are automatically applied to any implementations (assuming the appropriate rewriter options are turned on).

The next listing shows a simple interface with a contract class and an implementation.

Listing 15.8. Specifying contracts for an interface

This is basically the simplest interface I could imagine with useful pre- and postconditions. It’s meant to convert a string to a particular case (lower, upper, title, and so on). You should never pass in a null reference, and implementations should never return a null reference. The interface specifies that its contracts are in ICaseConverterContracts , and that refers back to the interface . The suggested convention is to name the contract class after the interface, just with a Contracts suffix. This looks slightly odd, as there’s then a class with an I-prefixed name, but it’s effectively just representing metadata about the interface. It’s not a normal class in terms of implementing real behavior. (The CLR considers it to be an entirely normal class, of course—only the Code Contracts tools and we as developers make the distinction.) You may wish to consider keeping the contracts class in the same file as the interface, again with the justification that it’s really just metadata and not a separate concept.[9]

9 If C# allowed interfaces to declare nested types, this would be an ideal situation to use that ability. Unfortunately, it doesn’t.

In the contracts-only implementation of Convert, we express the precondition and postcondition in the normal way before returning a default value . You could explicitly return null of course—I just find that using default (...) gives more of a hint that this isn’t meant to be treated as a real result. Of course this would actually violate the postcondition if we executed it, but that doesn’t matter, as this code is only present for the sake of the contracts. To make sure that we never really create an instance of the contract class, I’ve given it a private constructor which is never called from the class itself . I’ve also made it internal so that it won’t confuse developers in other projects.

Finally we’ve implemented the interface in a normal way in CurrentCultureUpperCaseFormatter. The implementation doesn’t specify any contracts or do any checks itself . Instead it relies on the binary rewriter to enforce the contracts at execution time.

Admittedly the contract is separated from the interface itself, but apart from that, this is a great situation to be in. We don’t have to test that the interface implementations honor the preconditions, and although we may write tests to try to provoke the postconditions being violated in corner cases, we can be confident that such violations won’t silently be propagated to calling code (assuming the appropriate rewriter settings, of course). Callers can also be certain of what they’re allowed to do—the preconditions are clearly stated, and implementations can’t have added their own ones. Of course there’s nothing to stop an implementation from checking and throwing an ArgumentException anyway, but in a system based on Code Contracts, this is a conscious violation of best practices, rather than the accidental introduction of an extra requirement.

15.3.3. Contract reference assemblies

Code Contracts has more capabilities up its virtual sleeves. Sometimes you may not want the contracts to be present in the executable code, but you want to let callers use the contracts anyway. Another tool (ccrefgen) lets you build a contract reference assembly to distribute along with your normal assembly. The contract reference assembly contains all the types, interfaces, methods, and so on of the original assembly, but with no implementation except the original contracts. It’ll have the same name as the original assembly, but with .Contracts at the end. For example, an assembly of SkeetySoft.Media would have a contract reference assembly called SkeetySoft.Media.Contracts.

When another developer adds a reference to your main assembly, the Code Contract tools will look for the contract reference assembly to go with it. If it finds the contracts, it can use those for static checking and also enforce the preconditions in the caller’s assembly. For example, consider the code in the following listing, which is split between a simple library class and a call to it.

Listing 15.9. Adding preconditions at the call site

Suppose the class library is built with execution-time contract checking turned off, but with a separate contract reference assembly. The calling assembly can tick Call-site Requires Checking in the Code Contacts project property page, at which point the last line is converted into something like this:

System.Diagnostics.Contracts.Wrappers.ContractAssemblyDemo.
PreconditionDemo.NV$DontPassInNull(new PreconditionDemo(), "hello");

The extra type here has been built into the calling assembly; its NV$DontPassInNull method executes the preconditions copied from the contract reference assembly (in the normal way, with calls to __ContractsRuntime.Requires) and then calls the real DontPassInNull method if the preconditions pass. It’s all seamless to the caller, which gets the same behavior as if preconditions were turned on in the target assembly. This way the caller gets to choose whether it wants contracts enforced, without requiring two different copies of the same assembly (one with contracts enabled and one without).

 

Only Preconditions are Copied

Using Call-site Requires Checking doesn’t enforce postconditions or invariants. In some cases it wouldn’t be able to—they can refer to the internal state of an object, which may not be visible to the caller. That shouldn’t be a problem—you do trust the code you’re calling to be perfect, don’t you? Seriously, it is a matter of trust—and knowing what to expect. If you believe that it’s more likely that there’s a bug in your code than the code you’re calling (which is certainly the case when I’m developing against the BCL, for example) then there’s still a lot of value to having just the preconditions checked.

 

Of course if you turn this feature on and the target assembly also has execution-time checking, you’ll end up testing the preconditions twice, which isn’t ideal.

15.3.4. Failure behavior

So far we’ve looked carefully at how to express the contracts and whether they’re checked, but hardly considered what happens when they’re violated. The behavior on failure is relatively complicated and highly tweakable, but it usually boils down to three possible options:

  • A normal exception type will be thrown if you’ve specified one in a precondition.
  • The system may raise an assertion error window or break into the debugger if you’re already debugging.
  • A ContractException (created by the binary rewriter) will be thrown otherwise.

The decision for whether to provoke an assertion failure or throw a ContractException is controlled by the Assert on Contract Failure option in the project properties. Note that it’s an either/or option. If you trigger an assertion failure but then ignore it, the code will proceed normally—it doesn’t throw a ContractException afterward. ContractException is deliberately designed to be uncatchable—you can’t refer to it in your own code. This is like the C# compiler generating unspeakable names for anonymous types and iterators.

The only way of catching a ContractException is to catch Exception. This is usually reserved for the top level of an application’s stack, where you might want to prevent one bad request from bringing down a whole server—although you generally need to be careful of situations where you should terminate the whole process anyway. The rationale for this is that you should never be catching contract violations: they indicate bugs rather than some external failure, and it’s hard to sensibly proceed in the face of “I’m calling code and something’s gone wrong, but I’ve no idea what.”

All of this talk of exceptions and assertions is assuming you haven’t included any custom error handling of your own. A global event is raised whenever a contract fails: Contract.ContractFailed. This allows subscribers to observe the failure and optionally state that it has been handled. A handled failure won’t trigger an exception or break into the debugger. The following listing shows an example of this sort of masking, as well as showing what information is available in the event.

Listing 15.10. Masking a contract with Contract.ContractFailed

We start off with a method with a precondition . This could be any contract that’s easily violated, but we’re just checking for argument non-nullity. Nothing new here. If the precondition is satisfied, we print out a diagnostic message.

HandleFailure is the method we’re going to use to create an EventHandler<ContractFailedEventArgs> delegate for the ContractFailed event. First it writes out the kind of failure (precondition, postcondition, invariant, assertion, or assumption), the condition that failed (in this case text != null), and the message (if any—in this case “Don’t pass in null”). It then claims that we’ve handled the failure. If there are multiple handlers, they’ll still all get called, but only one handler needs to call SetHandled for the failure to be considered as handled. ContractFailedEventArgs also has a SetUnwind method (not shown in this example), which has a similar but opposite effect: it ensures that even if SetHandled has been called, the normal escalation policy is still applied.

To test the method, we first attach the event handler and then call the method in a way that’ll violate the precondition . Despite the failure, we still get into the method body. Here’s the output:

Precodition: text != null; Don't pass in null
In method body

Another way of influencing what happens on contract failure is to use custom rewriter methods. In the project properties page, you can specify an assembly and class to use. Any of the static methods present in that class which match the signatures used by the contract’s runtime will be used instead of the default behavior. For example, if you want to change how assertions are handled, you’d write a method like this:

public static void Assert(bool cond, string userMsg, string condText)
{
Console.WriteLine("Checking condition {0}", condText);
Console.WriteLine("Result of check? {0}", cond);
}

Any required methods that aren’t available in the class are given the usual behavior. See the documentation provided with the Code Contracts download for the other method signatures.

Changing the failure behavior either for a whole assembly (using custom methods) or a whole AppDomain (using the ContractFailed event) isn’t something you’ll want to do for normal applications. It’s mostly useful if you’re writing a custom framework that’ll execute third-party code: a test harness or a plug-in system, for example. It’s worth knowing about what can happen, mostly so that if you’re executing in an environment that does change the failure mode, you won’t be surprised. I expect most mainstream unit test frameworks to gain support for Code Contracts in the near future. Most of the time, you should be thinking about any differences in behavior you want to see between a debug build and a release build. We’ll discuss these decisions later.

As we’ve seen, the precise behavior of a contract failure depends on many factors—a full treatment is beyond the scope of this book, and would be irrelevant to most developers. For more details, you can consult the documentation—also I’d recommend posting on the Code Contracts user forum if you want to check anything particularly out of the ordinary (see http://mng.bz/43E0). The Code Contracts team monitors the forum closely, and can provide advice taking into account the many available options and their implications.

The binary rewriter’s job is to change how the code behaves at execution time. The next tool we’ll look at is the static checker, which affects how your code behaves at compile time.

15.4. Static checking

The static checker (cccheck) checks at compile time that you won’t break contracts at execution time. In some ways, the static typing we’ve been used to for years is a restrictive version of what the static checker can do. Just as the normal C# compiler checks that your code obeys the “type contracts” in every method we declare (the number and types of the parameters, for example), the static checker analyzes the more complex contracts expressed earlier and warns you if it believes you may break them.

Currently, the static checker is only available if you’re either using Code Contracts under the academic license or you have the Visual Studio 2010 Premium or Ultimate edition installed. This may change in the future, but even if you can’t use the static checker yourself, it’s worth being aware of what it can and can’t do. This will help you to think in terms of contracts, leading to more robust and understandable code that leaves fellow developers in less doubt as to how they should interact with it. Whether or not you use an automated checker, more information is always useful when you perform your own mental checking for your code’s correctness.

15.4.1. Getting started with static checking

Let’s look at a simple example first. Yet again, it deals with nullity of input and output values. I should probably emphasize that contracts can be a lot more complex than this, but in my experience nullity is the single biggest irritation in terms of knowing what an API expects and will provide. It’s not surprising that it gained its own syntax in Spec#, or that F# avoids even the possibility of null values wherever it can. It also helps that it’s extremely easy to demonstrate in examples. The following listing asks the static checker to prove a number of contracts—some successfully, and some not.

Listing 15.11. Experimenting with the static checker and simple contracts

To work out what the static checker is going to do, we have to think about where things might go wrong. Preconditions need to be checked at call sites, invariants need to be checked at each exit point of each public method, and postconditions need to be checked at each exit point of the method they’re declared in. Assertions and assumptions are checked at their location within the program text. Neither invariants nor normal postconditions (simple Ensures calls) are checked if the method throws an exception. In listing 15.11 we have four contracts to check: the postcondition of DontPassMeNull (once; there’s only one exit point) and the precondition of the same method (we call it three times).

The postcondition check passes: the checker knows that input can’t be null due to the precondition. Likewise the first call to DontPassMeNull will definitely pass —the string literal is definitely not null. After that, things get trickier. The next line might not be a bug, and by inspection we can tell that MightReturnNull never actually returns a null reference. The precondition will always pass—but the checker can’t prove it. It doesn’t try to infer a postcondition of return value non-nullity for MightReturnNull, even though it could prove that such a contract would always pass. It doesn’t know that the precondition will always fail, either, so it reports a result of “unproven.” The final call is easy: the checker knows that the precondition will never pass, so it reports a definite failure. Figure 15.2 shows the results in the Error List window in Visual Studio.

Figure 15.2. Static check results in Visual Studio 2010

Before I move on from this example, I want to go back to the point about how the checker treats MightReturnNull. It’s tempting to think of this as a limitation of the checker, but it’s not.[10] If a method wants to say that it guarantees never to return a null reference, it should declare that as a contract. If it doesn’t make that guarantee, then a later change to return a null reference is valid—it still conforms to the contract of the method. To go back to our static typing analogy, it’s like a method that’s declared to return IEnumerable<string>. You may happen to know that the current implementation always returns a List<string>, but it’d be unwise to blindly cast the result: a future implementation could use an iterator block or return an array, for example. Of course, if you come across this situation in your code, you may decide that the method really should guarantee that it returns a non-null value; the correct fix is to add the contract. Otherwise, you can either use Contract.Assume or explicitly handle the case where it returns null.

10 In fact, you can change this behavior with the -infer option to the checker. By default the checker will infer postconditions for properties, but not methods. There’s a -suggest option that displays postconditions you might like to consider adding, but it doesn’t use this knowledge when checking for correctness.

 

The Static Checker Stops on Failure

If the checker detects that a certain call will always fail a precondition (or that an assertion will always fail) then it treats the end of the call as unreachable. Any other statements that could normally only be reached via that point of failure aren’t checked for correctness. That means when you fix one problem, you may find there was another one waiting on the next line, which hadn’t been reported because the checker knew you’d already have failed by then.

 

On the other hand, some requirements don’t need to be explicitly stated... the static checker is happy to try to prove them for you anyway.

15.4.2. Implicit obligations

Whenever you call an instance member (a real one, not an extension method) on a reference type value, there’s an implicit requirement that the reference mustn’t be null. If you turn on the Implicit Non-null Obligations option then the checker will detect potential problems of dereferencing null values.

Implicit Non-Null Obligations

One way to think about implicit non-null obligations is to imagine that every instance member on every reference type started with a precondition like this:

Contract.Requires(this != null);

If you turn on the Implicit Non-null Obligations option in Visual Studio, the checker tries to prove that obligation—again, using the contracts available on other members. The following listing shows an example of this, fetching strings from methods or using a literal—and then trying to dereference the relevant variables.

Listing 15.12. Testing implicit non-null obligations

This is similar to listing 15.11, but using implicit contracts instead of an explicit precondition. We have three variables —one initialized with a string literal, one initialized with a method that has a postcondition to guarantee that it won’t return null, and one initialized with a method that doesn’t make any guarantees. When we try to print out the length of each string , the first two calls are fine, but the checker reports a warning on the last one: “Possibly calling a method on a null reference ‘mightBeNull’.”

Of course, as with any contract, the checker can perform a lot more complex reasoning than this. There may be several code paths that initialize the variable, and so long as the checker can prove that any time it’s deferenced it’s definitely not null, it won’t issue a warning. I want to highlight this explicitly because all of the examples in this chapter are quite simple—that’s the nature of book examples—but real-world code tends to have more complexity. If you use the checker against your own code, you’ll see just how much it can work out—or how many possible bugs are lurking in your source.

Implicit Array Bounds Obligations

Another implicit obligation occurs when accessing arrays. Though .NET arrays can have a nonzero lower bound, any single-dimensional array accessed directly with an indexer in C# has to be a vector in CLR terminology. These are much faster than rectangular arrays and arrays with a nonzero lower bound, and the static checker can attempt to prove that you never violate either bound if you have the Implicit Array Bounds Obligations option ticked. The following listing shows a simple example of where you might go wrong.

Listing 15.13. Invalid indexing due to a typo

We’ve accidentally used <= instead of < in the for statement . Normally this would only show up at execution time (hopefully in a test), but with Code Contracts, the checker reports a compile-time warning of “Array access might be above the upper bound.” In other cases it’ll be more definite, with warnings such as “Array access IS above the upper bound.” The exact details of the message depend on whether the checker detects that the code will fail every time the expression is evaluated or only on some occasions. In this case, although it’ll definitely fail eventually, it’ll be okay for the first args.Length iterations—hence the “might” part of the warning.

That’s relatively simple—it’s pretty obvious that we’ll be venturing outside the bounds of the array. The checker can be somewhat more impressive, though. It’s reasonably common when working with arrays to iterate through one array to populate another. The sizes of the arrays are related, but not necessarily the same. The following listing shows an example of this, populating a new string array by alternating between a value from an original array and the default value (null).

Listing 15.14. More complex array bounds checking
static void Main(string[] args)
{
string[] copy = new string[args.Length * 2 - 1];
for (int i = 0; i < args.Length; i++)
{
copy[i * 2] = args[i];
}
}

Here the access to args[i] is obviously okay, but what about copy[i * 2]? The checker detects the relationship between the lengths of the two arrays, and performs arithmetic and range analysis to check whether the index is still valid. If you look carefully at the size of the new array, you’ll see I’ve deliberately reduced the size by one to avoid having a trailing null value—so that a copy of ["a", "b", "c"] becomes ["a", null, "b", null, "c"], for example. If you change the array index used to copy[i * 2 + 1], the checker will realize that on the last iteration, that’ll go out of bounds. Maybe I’m easily impressed, but I think that’s pretty clever.

Even that’s not all—we still have a potential problem, even in this code. We won’t access any invalid indexes in the array, but what if the original array (args) is empty? We’ll end up trying to create a new array with a negative size. The checker spots this and adds a warning: “Suggested precondition: Contract.Requires(0 <= ((int)(args.Length) * 2 – 1));.” This precondition is stricter than the simpler precondition we might’ve coded by hand (Contract.Requires(args.Length > 0)) to cover the case where the array length is so big that doubling it overflows the bounds of Int32.

You might be wondering why it hasn’t also prompted us to require that args not be null. The answer is that it normally would, but it realises that Main is an entry point, and so in normal use args won’t be null anyway.

Implicit Arithmetic Obligations

The final kind of implicit obligation is arithmetic. Currently there are two kinds of arithmetic checking provided: division by zero, and negation of the minimum value of signed integer types. In many ways the latter is a more insidious problem than the former: at least if you try to divide by zero you’ll get an exception, rather than bad data. To show the danger of negating minimal integers, the following listing shows a flawed implementation of IComparer<T>.

Listing 15.15. An incorrect implementation of a “reverse comparer”
public class BadReverseComparer<T> : IComparer<T>
{
private readonly IComparer<T> original;

public BadReverseComparer(IComparer<T> original)
{
Contract.Requires(original != null);
this.original = original;
}

public int Compare(T x, T y)
{
return -original.Compare(x, y);
}
}

The aim of listing 15.15 is to reverse the order of an existing comparison. IComparer <T> is a nicely composable interface: you can write implementations that chain to other comparisons to provide a secondary sort order, compare two elements by properties, or reverse the comparison order like we’re attempting here—it’s great. Unfortunately, there’s a nasty trap waiting in this implementation—a trap that unit tests alone may well not spot. This implementation works perfectly well except in one specific situation: when the value returned by original.Compare is int.MinValue. Due to the range of integers available, -int.MinValue is still int.MinValue, so that particular comparison wouldn’t be reversed. Fortunately, when you have Implicit Arithmetic Obligations turned on, Code Contracts spots this potential problem and issues a warning: “Possible negation of MinValue of type Int32.” Just in case you’re wondering, the correct[11] fix to this is to reverse the order of the arguments passed to the original comparison, like this:

11 That’s “correct” for the intention of reversing all comparisons. It violates the documentation of IComparer<T>, which states that a null reference is considered less than any non-null reference, assuming that the original comparison obeys the same rule.

public int Compare(T x, T y)
{
return original.Compare(y, x);
}

Obviously the checker performs appropriate analysis first: it won’t report a warning if it can prove that the value you’ll be negating can never be the minimum value for the type. Although only two checks are performed at the moment, I wouldn’t be surprised to see more added later, such as possible overflows in a checked context.

You may be wondering why all these are only options—options which are turned off by default. It turns out you can have too much of a good thing.

15.4.3. Selective checking

It’s not often you see documentation for a product that pretty much discourages you from using it, but the Code Contracts user manual is blunt about static checking being tricky to use effectively. Aside from some fairly subtle behavior, the biggest problem is likely to be information overload. It’s one thing to start a project from scratch and use static checking every step of the way, but applying it to an existing code base can be daunting. Just as an example, I imported my small utility project (MiscUtil—see http://mng.bz/xDMt) and turned on static checking for normal contracts and all the implicit obligations. After I’d turned up the maximum number of warnings, the checker found 555 unproven contracts and suggested 220 preconditions. This is overwhelming even for a relatively small amount of code—for a full commercial application it’d be a positive avalanche.

Code Contracts provides two ways of managing this situation: baselines and an attribute to control what’s checked.

Using Baselines to Highlight New Issues

Suppose you want to start using Code Contracts on an existing code base that currently raises thousands of warnings in the static checker. There are two major concerns: first, you want to make sure the code doesn’t get any worse. You should avoid introducing any new violations. Second, you want to nibble away at the warnings a chunk at a time. Baselines help with the first problem.

The idea of a baseline is that it’s a “known bad” build result. Usually in software engineering we have known good versions, but in this case we know that our code is bad in terms of having lots of unprovable contracts—we need to know where it’s bad. To use baselines you just specify a filename in the Code Contracts project properties. This is relative to the location of the assembly that’s being checked: the default value is .. ..aseline.xml, which will be in the project’s root directory for default build configurations.

When the static checker is invoked, it first looks for an existing baseline file. If the file doesn’t exist, the check is performed as normal and the results are written to the baseline file. Otherwise, the checker loads the results from the existing file and doesn’t report errors it had already seen, only showing new problems. A new file is also generated with the new problems. The new file has the same name as the normal baseline file, but with .new appended to the end. The files are just simple XML, so you can easily analyze them with external tools if you want to, merge them together (order isn’t important in the file), and include them in continuous build reports. In addition to preventing new issues, you could also use baselines to show positive progress: as you fix some issues, you can rename the baseline file, rebuild, and then see how many problems have been fixed by comparing the two.

Another approach to managing an initially unwieldy code base is to only perform static checking on certain parts of the project.

Using [ContractVerification] to Control Checking

If you’re trying to actively remove some of the existing warnings produced by the static checker, it can help to focus on one piece of code at a time. You can apply the [ContractVerification] attribute to specify whether an assembly, type, or individual member should be checked. The following listing shows how simple it is.

Listing 15.16. Applying checking selectively with [ContractVerification]

Obviously there’s nothing to be checked in any of the methods in listing 15.16, but the names should be clear enough. The main point of the listing is to demonstrate how pseudo-inheritance of contract verification works. Each type inherits the assembly’s attribute value unless it specifies the attribute itself, and likewise each member inherits the value from its containing type. So in listing 15.16, although the assembly-level attribute turns off static checking , it can be turned back on at the type or member level —and turned off again at the member level if it’s turned on for the type. It’s important to note that this is not related to normal type inheritance. A class derived from CheckedType within the same assembly wouldn’t be checked by default, for example.

One subtlety is worth knowing about as well. As we’ve seen in previous chapters, in some cases the C# compiler creates extra types and methods for you—in particular, for anonymous functions and iterator blocks. The C# compiler doesn’t know anything about [ContractVerification], so it doesn’t propagate the value to any extra members created as a result of complex transformations. For example, if UncheckedType.CheckedMethod used a complex lambda expression in its body, that code wouldn’t be checked, because as far as the static checker is concerned, the code would be in a separate method without the attribute applied to it.

With judicious use of this attribute, you can choose to tackle one type or even one method at a time, fixing up any contractual requirements as you go. One other reason to apply this attribute may be if your codebase is too large to run the static checker over during development—while implementing a new class or subsystem, you may want to only check the new code, leaving full checking of the whole project to the continuous build system. You could temporarily add [ContractVerification(false)] to the whole assembly, and then add [ContractVerification(true)] to the new types. To avoid the danger of accidentally checking this into source control and disabling static checking for everyone, you might want to define a preprocessor symbol for this purpose, and add code like the following to AssemblyInfo.cs:

#if SELECTIVE_STATIC_CHECKING
[assembly:ContractVerification(false)]
#endif

You can then define a build configuration based on Debug but including that symbol, making it trivial to develop with selective checking turned on.

The final tool available is ccdocgen, which doesn’t require Visual Studio Premium or Ultimate; it generates XML documentation from your contracts.

15.5. Documenting contracts with ccdocgen

This is one area of contracts that’s simple from the point of view of the code you write: you don’t need to change a thing in order to document your contracts. Simply tick the Emit Contracts into XML Doc File check box, and when you build your normal XML documentation, the contracts will be emitted too. Listing 15.17 shows a class with a single public method including contracts, and an invariant.

Listing 15.17. Automatically documenting method contracts with ccdocgen
/// <summary>
/// Class summary.
/// </summary>
public sealed class DocDemo
{
private int callCount = 0;

[ContractInvariantMethod]
private void Invariant()
{
Contract.Invariant(callCount >= 0);
Contract.Invariant(callCount < 100, "Wrap at 100.");
}

/// <summary>
/// Method summary.
/// </summary>
/// <returns>The input, reversed.</returns>
public string Reverse(string text)
{
Contract.Requires<ArgumentNullException>(text != null, "text");
Contract.Ensures(text != null);
callCount = (callCount + 1) % 100;
char[] chars = text.ToCharArray();
Array.Reverse(chars);
return new string(chars);
}
}

There’s nothing remarkable here in terms of the contracts. For the sake of showing variety in the generated XML, I’ve specified a description in one Contract.Invariant call and forced the use of ArgumentNullException for the precondition in the method. The complete generated XML documentation for the class looks like this (reformatted slightly):

<doc>
<assembly><name>CcDoc</name></assembly>
<members>
<member name="T:CcDoc.DocDemo">
<summary>Class summary.</summary>
<invariant>callCount &gt;= 0</invariant>
<invariant description="Wrap at 100.">
callCount &lt; 100
</invariant>
</member>
<member name="M:CcDoc.DocDemo.Reverse(System.String)">
<summary>Method summary.</summary>
<returns>The input, reversed.</returns>
<requires description="text"
exception="T:System.ArgumentNullException">
text != null
</requires>
<exception cref="T:System.ArgumentNullException">
text == null
</exception>
<ensures>text != null</ensures>
</member>
</members>
</doc>

It’s fairly simple, but there are a few things to note about the generated documentation:

  • The text of the contract elements comes from the code: in some cases this can cause private information to leak into documentation, such as the name of the callCount variable. This isn’t much of a problem, but you should be aware of it—and make sure your variables have appropriate names! Adding a description to the contract method call can add clarity here; it’ll be emitted in the description attribute.
  • An exception element has been generated for us because we explicitly specified the exception to throw if the precondition isn’t met. If you let Code Contracts throw the default ContractException, this element isn’t generated.
  • The requires element also specifies the exception that’ll be thrown if the precondition fails; again, this would be omitted in the default case.

Some other elements can be generated; at the time of this writing this list only consists of pure (for pure methods) and ensuresOnThrow (for postconditions that apply even when exceptions are thrown). Likewise the documentation can indicate when contracts have been inherited from a base class or interface. I’ve omitted these features from the example for the sake of brevity, but the Code Contracts documentation goes into more detail.

Once you have the XML, you’re free to do with it as you please. The Code Contracts documentation gives instructions for patching Sandcastle to make it render the elements appropriately, and no doubt other documentation transformation tools will adapt to include them in the future. Unfortunately, at the time of this writing Visual Studio’s own IntelliSense doesn’t display the contracts within the IDE, making the feature slightly less valuable. But it’s possible that plug-ins may improve this situation over time. We still have the core benefit that the contracts are expressed in a single place, and then used for documentation, compile-time checking, and execution-time checking. There’s no way for the three aspects to get out of sync with each other.

Now that we’ve looked at the tools, let’s consider some of the broader questions raised by Code Contracts.

15.6. Practical contracts

 

May Contain Nuts

This section is very subjective, and contains only trace amounts of technical information. If you’re happy enough to work out the best way of using contracts for yourself, you won’t miss out on anything by skipping to the chapter summary.

 

Unless you happen to have used a language supporting Design by Contract before, you may sometimes find yourself unsure of how to proceed with Code Contracts. If you’re using it in conjunction with test-driven development, what should you write first: the contract or the implementation? Should you write unit tests for the contracts? When is it appropriate to let ContractException be thrown, and when should you throw a standard .NET exception such as ArgumentNullException? Should your release builds check contracts or not?

We’ll think about all of these questions in this section, but I don’t promise to come up with concrete answers for everything. At the time of this writing, Code Contracts is a young and evolving product. Nobody has much experience with it, and I don’t claim to be an exception. Furthermore, many of these decisions are heavily dependent on your exact situation, and some are a matter of personal taste too. Hopefully with the discussion in this section, you’ll be in a good position to work out a strategy that’s right for you and your team.

The Code Contracts user manual has guidance too, including situations where you don’t want to run the binary rewriter at all. For the rest of this section I’ve assumed that you’re happy to run the rewriter: it gives you a lot more control and options for no real disadvantages other than build time.

15.6.1. Philosophy: what’s in a contract?

First, it’s worth thinking about what contracts mean to you—in particular what preconditions mean. To some people, they indicate the expected input states under which the method guarantees to operate correctly. This is a bit like having a warranty for a vacuum cleaner, which means the manufacturer will repair it if it breaks under normal conditions. They’re not going to fix the cleaner if you start attacking it with a hammer, and the company won’t try to guarantee you won’t be injured in such a situation either. In other words, if you break the terms of the warranty, all bets are off. People who regard contracts in this way are likely to have Debug.Assert calls within their existing code: they’re measures to help you iron out any wrinkles in your code before you ship, but if a bug creeps through and violates the preconditions in the released code, there’s no telling what might happen. Likewise with postconditions: you’ve made a best effort to ensure that all the bugs have been fixed during development, but if a bug is still lurking, you could end up with an invalid result. There probably won’t be unit tests for failing preconditions, because there’s no particular expected behavior.

To other people, contracts are a firmer guarantee: they not only say that the code will execute in a particular way if the preconditions are met, but also that the code won’t execute at all if they fail. This is more like a height limit for a roller-coaster ride: the theme park isn’t just willing to guarantee your safety if you’re above a certain height, but they’ll actively prevent you from putting yourself into danger if you fail to meet their criteria. Developers with this mentality are more likely to have explicit tests for bad argument values, throwing ArgumentNullException and so on, regardless of whether the code is built in debug or release mode. Postconditions have been harder to express until now, but this attitude is likely to encourage their enforcement in release builds too: a guarantee that the method really will never silently return a value that the contract forbids, or leave the object in an invalid state. Preconditions are likely to have unit tests, as otherwise there’s nothing to test the guarantees.

It’s worth noting that these different groups may agree on what the contracts for any particular operation should be: whether a particular value is a valid input, whether the method should guarantee the range of its return value, and so on. The difference is in what the behavior should be when that contract is violated. I’m not going to claim that either attitude is wrong, although I tend to favour the latter approach. I generally dislike code that behaves significantly differently in a debug build than in a release build. Whichever side you come down on, try to achieve consistency within a project—which for most developers will mean discussing the issue with other team members.

15.6.2. How do I get started?

Everyone has a different development style. Personally I like test-first coding, although I’m not as strict with myself as I’d like to be, and I couldn’t really claim that all my design is test-driven. Before contracts, you already had the choice of whether to design the API first, the implementation first (changing the design as you went along), or the tests first. Now we have to add contracts into the mixture. Fortunately, I don’t think it’s as bad as it sounds, because I think each of those steps naturally yields its own set of contracts.

Sometimes tests will provoke contracts—usually preconditions. When you’re writing success case unit tests, think about what else you could be passing into the method, or other ways you could set up the object. Are there some combinations or arguments that don’t make sense? Can you express them as contracts?

Sometimes the implementation will provoke contracts, both private ones (assertions and assumptions) and public ones (usually postconditions). It can be hard to know exactly what your code is willing to guarantee until you’ve written it, but if you can see something that’ll certainly be true when you exit, consider telling the caller about it as a postcondition.

Invariants are more likely to come out of the higher-level design of the class, as they affect the whole type instead of specific members. One possibly obvious piece of advice: don’t even think about invariants for immutable types. If something can’t vary its state, it can’t break an invariant. Instead, if there are rules that must be adhered to on construction, those should be preconditions.

Don’t worry about capturing absolutely everything, though. Just like with unit testing, it’s better to have a few good contracts than decide that because you don’t have enough time to put full functional contracts in for everything, you won’t bother at all. Likewise it’s worth thinking carefully about what you guarantee: though a weak postcondition is less useful for callers right now, it does give you more flexibility in the future. Try to think about the logical guarantees you want to make, even if the implementation can guarantee a lot more.

Unit Testing Contracts

With legacy contracts, I tend to write unit tests to prove the contracts. Sometimes this feels like a waste of time—if you have several parameters, none of which can be null, having a test for each of them can get extremely boring. But it does prove that the behavior matches the documentation. With Code Contracts, you get that for free: if the autogenerated documentation includes a contract, it must be present in the code. That doesn’t mean the contracts will be checked at execution time, of course—but unless you run your unit tests with every build configuration, a test couldn’t check that anyway. I find it’s particularly clean when you’re implementing an interface, as then most of the contracts will be specified entirely separately from your implementation anyway, so there’s less of a feeling of cheating.

It’s entirely reasonable to write unit tests to provoke corner cases that you suspect may break the contracts, of course. That’s just normal testing where you should test the expected result, and you’ll get the added benefit of the contract performing sanity checking too.

If you decide you do want to test that your contracts are present and being checked, you may find a slight problem if you’re using the default ContractException. It’s designed to be uncatchable at a fine-grained level, which makes it hard to use in traditional test framework “expect this action to throw this exception” assertions. I suspect that test frameworks will gradually evolve to include explicit support for this scenario, but until then one alternative is to use your own custom rewriter methods in a debug build. For instance, they could throw a publicly available exception instead of the hidden ContractException, in which case you could expect that public exception just like any other failure. All of this is obviously unnecessary if you’re using the old-style exceptions. Speaking of that sort of choice, let’s think about how you might want to configure Code Contracts in the first place.

15.6.3. Options, options everywhere

You can’t fault Code Contracts when it comes to flexibility. Combining the various features of the tools with different build configurations, you can achieve almost any effect you want. The difficult part isn’t the tweaking—it’s deciding what you want to start with.

Choosing a Failure Mode

Unless you start creating your own custom rewriter methods or subscribing to the ContractFailed event, you have four mutually exclusive options for what should happen if a contract is violated:

  • The application stops with an assertion failure, allowing you to break into the debugger.
  • A ContractException is thrown, which can’t be caught except as a blanket Exception.
  • A standard .NET exception is thrown, which can be caught by client code.
  • Nothing—the code continues as if no contracts were involved.

Some of this can be decided on a per-configuration basis—in particular, whether to use ContractException or assertions, and how many contracts to check—whereas the decision to use standard .NET exceptions requires the types to be specified in the code itself. Though you could write every precondition twice, using preprocessor symbols to determine which to use for a given configuration, it sounds like a step too far to me.

Unless you’re migrating an existing project with legacy contracts to use Code Contracts, I’d personally recommend using the nongeneric Requires method, which will either assert or throw a ContractException. It results in the simplest code, and you don’t have to repeat the parameter name for ArgumentException-related preconditions. The familiarity of existing exceptions tugs at me a little, but fundamentally the type of the exception doesn’t provide any extra information beyond what’s already in the contract—and removing the possibility of catching specific exceptions is a step toward encouraging appropriate exception handling policies. One disadvantage of ContractException is that because you can’t explicitly catch it, it’s hard to write unit tests to check your contracts, as we’ve just seen.

If you build a contract reference assembly, you can let your callers have some control over what happens too. There’s little point in building a reference assembly if the contracts are present in the rewritten binary anyway, though. Having said that, a reference assembly will only help with certain contracts.

Contract Types

Different contract types can have different behavior associated with them. There isn’t complete freedom about what to do here—you can’t easily make some contracts fail with a ContractException and others fail with an assertion error, for example—but the binary rewriter does let you specify the general level of contracts to keep in the rewritten binary:

  • None— All contracts, including legacy ones, will be removed.
  • Release requires— Legacy contracts and preconditions that specify a standard .NET exception will be included.
  • Preconditions— As above, but with preconditions throwing ContractException included as well.
  • Pre and post— As above, but with Contract.Ensures (and Contract.EnsuresOnThrow) calls included.
  • Everything— The above, with invariants, assertions, and assumptions included.

If you really want to include some of the later items but exclude earlier ones, you could use C# preprocessor directives to achieve another degree of flexibility. For example, you may want full contract checking in an ideal world, but have some postconditions that are just too expensive to validate in release builds. You could use a preprocessor symbol of EXPENSIVE_CONTRACTS and only define it in debug builds, or even have a separate build configuration. That leads us to consider what kinds of build you want in the first place.

 

Different Choices for Different Projects

This is a good example of where different projects may have different requirements. The BCL team is scrupulous in unit testing their contracts, and their binaries ship with a relatively small set of contracts included at execution time. They’re in a fairly unique position—they have relatively little idea of how the code is going to be used, so any performance impact from contracts could be serious. They also don’t have the luxury of letting users decide which version to run against—we really don’t want to start having different configurations of .NET installed on end-user machines for different contract preferences. Your own requirements will no doubt be different, so think about them carefully.

 

Additionally, there’s the question of where the contracts are applied. If your code has a lot of contracts for debugging and verification purposes but at execution time you mostly care about the behavior at the boundaries between your code and third-party assemblies, you can turn on the Only Public Surface Contracts option.

Build Configurations

Visual Studio creates projects with Debug and Release configurations by default. The general idea is that you develop using the Debug configuration but then ship using Release. But what counts as “shipping”? Code is used in an increasingly diverse way—shipping a shrink-wrapped consumer application is very different from deploying your code to the one-and-only server running your production web service, which is also different from releasing a new version of an open source library. Try to work out who’ll want to use the code and in what context. If you’re building a class library, do you know the other developers and their needs? Will some developers be concerned about the performance of checking contracts frequently? Are they likely to know about Code Contracts, and perhaps want to use the static checker against your library’s contracts (even if perhaps you don’t use the checker yourself)?

If you’re building an application, so the code won’t be consumed by other developers, only users, that makes life easier: you can decide the behavior you want to give you confidence that the application won’t malfunction, and tune the settings accordingly. Open source projects are easy in the other direction: at least then if you don’t guess your users’ needs correctly, they can change the settings and rebuild the code themselves. The hardest situation is perhaps that of the component vendor, shipping class libraries as binaries to paying customers.

You can introduce more flexibility in what you ship by creating multiple build configurations—some with full checking, others with only public API checking of preconditions, and so on. Beware of the cost of maintaining a large number of configurations, though—especially if other variables are involved other than contracts. You probably don’t want to get into the business of building multiple versions to target different versions of the .NET framework and different levels of contracts and different optimization levels, and so on.

Assertion failures are reasonable for debug builds (whether you’re the one doing the debugging or not), but are almost certainly not right for anything that might reasonably be called a release build. This can be decided on a per-configuration basis easily from the options. I know this goes against my earlier point of debug and release builds behaving differently, but at least in both cases execution of that unit of work will halt—it’s just the difference between bubbling up a nearly uncatchable exception to a top-level handler and raising an ugly but attention-grabbing assertion window.

Why Not Validate Everything?

I’d generally suggest writing defensive code that validates both its inputs and its own behavior. There’s one obvious potential drawback: performance. Checking a contract is clearly more work than not checking it. If you stick to contracts that are cheap to validate, they’re unlikely to become a performance bottleneck other than for small methods called a huge number of times—but if you have any performance benchmarks, it’d be worth running them both with and without execution time contract checking so you can tell for sure. As ever, it’s hard to make accurate guesses about performance—so don’t. Gather data that’s as realistic as possible, and base your decision on that.

If you have internal methods that are called frequently, you may find that just restricting contracts to the public API is good enough. If you do turn execution-time contract checking off, and you’re building a class library, it makes sense to build a contract reference assembly. There are no downsides to this, other than the build taking slightly longer, and it at least gives others the option of running call site validation or static checking against your code.

15.7. Summary

I have high hopes for Code Contracts. I suspect it’ll take a while to gain traction, partly as it requires an additional download even before you get started, and partly because some of its goodness is currently only available to Visual Studio Premium and Ultimate users. But I believe it addresses some of the issues that have frustrated developers for a long time.

It’s worth acknowledging that part of the problem is that the type system in .NET isn’t quite rich enough to start with. If non-nullable reference types were embedded in .NET and C#, a whole class of preconditions and postconditions would be unnecessary now.[12] Likewise the fact that .NET doesn’t have any notion similar to const in C++ is a source of pain whenever you want to return a read-only view of an object to a caller, or declare that you won’t mutate the state of any incoming objects. Code Contracts doesn’t address this latter issue yet, but I wouldn’t be surprised to hear that engineers were thinking hard about it.

12 Admittedly non-nullable reference types come with their own set of design difficulties (see http://mng.bz/fVfI). It’s not like this was a simple oversight in the design of .NET.

Contracts become more helpful the more widely used they are, particularly in terms of static checking. There’s no guarantee that Code Contracts will become an industry-wide expectation—that in two years’ time you’d be considered mad to ship a commercial component library without a contracts reference assembly. Microsoft is effectively bootstrapping the ecosystem by adding contracts to the BCL, and we can hope that leading library vendors (both free and commercial) will adopt them over time. Until then, you can still benefit from them within your own code, in terms of simple execution-time checking, autogenerated documentation, automatic contract inheritance, possibly static analysis, and above all the encouragement to just stop and think about what you need and what you’re prepared to guarantee.

At a deep level, all code is about communication: expressing ideas about what you want to achieve. It’s no coincidence that if you look at the features C# has gained over the years, almost all of them involve communicating common and useful ideas in a simple manner. It’s one of the ways our industry is attempting to manage the increasing complexity we’re all faced with. Code Contracts is another weapon in the armory. Don’t just think of it as a way of making sure that your code isn’t faced with inappropriate values at execution time. Think of it as a means of letting your code speak with clarity and precision—whether that’s to the tools, the code maintainer, other developers using your API, or even yourself.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.9.147