1

I'm learning how to design by contract by annotating my existing code with Contract.Requires() and Contract.Ensures() wherever I can.

After fixing the warnings that were actually caused by me, I started to notice that many methods in the framework do not ensure their post conditions. This concerns me, because the static checker is now giving me false positives about possible violations of my preconditions.

An example of a method that doesn't implement Code Contracts:

CultureInfo.GetCultureInfo(string)

As stated by the documentation:

  • Empty input will result in an invariant culture object.
  • Bad input will result in an exception.

In no case will it ever return null. Still, I can't use this:

Contracts.Requires(culture != null)

If I do, the static checker gives me this:

CodeContracts: requires unproven: culture != null

So, what do I do? Ignore the warning and write a comment with a link to the documentation? Or is there a way to prove post conditions for a method that someone else wrote?

edit

Making assumptions seems to make the analyzer shut up, but only until the next time that I write the same line of code.

var culture = CultureInfo.GetCultureInfo("en");

Contract.Assume(culture != null);

MyPreconditionalMethod(culture);

I've looked at the [ContractClassFor()] attribute, but it requires a mutual handshake. :\

Steven Liekens
  • 13,266
  • 8
  • 59
  • 85

1 Answers1

2

Instead of Contracts.Requires(culture != null), you could try Contracts.Assume(culture != null). This gives the static analyzer a hint that, at that point in your code's execution, culture will not be null. The static analyzer will use this assumption when making further analysis on your code.

Update

So, if you have a method, say:

public int DoSomething(SomeObject o, int i)
{
    Contract.Requires(o != null);
    Contract.Requires(i > 0);
    // You could combine the conditionals in the Requires: o != null && i > 0

    Contract.Ensures(/* some post condition */);

    int returnValue = 0;
    // Do some stuff

    return returnValue;
}

public void SomeMethodThatDoesSomething(int i)
{
    Contract.Requires(i > 0)

    // Do some stuff
}

public void SomeMethodThatCoordinatesActivities()
{
    int result = DoSomething(new SomeObject(), 10);

    Contract.Assume(result > 0);
    SomeMethodThatDoesSomething(result);
}

The static analyzer won't be able to prove that result in SomeMethodThatCoordinatesActivities is greater than 0, so you'll get a contract requires unproven: i warning. By using Contract.Assume in the calling method, you give a hint to the static analyzer to assume that at that point, result will be greater than 0 when calling SomeMethodThatDoesSomething and the unproven warning will not be given.

One interesting thing to note in the code above is that if I do actually provide the following post condition on the method DoSomething:

Contract.Ensures(Contract.Result<int>() > 0);

then I wouldn't need the Contract.Assumes(...) call in SomeMethodThatCoordinatesActivities because I've told the static analyzer that when DoSomething returns, it's result will be greater than 0, so no assumption needs to be made. The static analyzer knows this will be true, and an unproven warning will never be given.

fourpastmidnight
  • 4,032
  • 1
  • 35
  • 48
  • @StevenLiekens I added a code example to explain where to use `Contract.Assume` and how it works for static analysis. I also have a blog post on this subject [here](http://discoveringcode.blogspot.com/2014/03/code-contracts-and-test-driven.html). – fourpastmidnight Jul 28 '14 at 00:31
  • Bookmarked. Your blog was way easier to understand than the documentation. – Steven Liekens Jul 28 '14 at 01:45
  • Is it common practice to create a wrapper (`DoSomethingByContract()`) that makes the assumption (`Contract.Assume(result > 0)`) before returning the value to the caller? – Steven Liekens Jul 28 '14 at 09:13
  • Can't help but feel like there is a huge gap that needs to be filled in the contracts framework. I like that you can define contracts in buddy classes, but it requires that the contract class acknowledges its buddy class. Any idea why there is nothing similar for classes like `CultureInfo` that do not define contracts already? – Steven Liekens Jul 28 '14 at 09:21
  • @StevenLiekens I wouldn't say it's a common practice. This was just an example to show what code might look like that produces the warning, and then the resulting Code Contracts that would eliminate the warning given the code structure. – fourpastmidnight Jul 28 '14 at 14:42