I’m trying to understand Code Contracts in a bit more detail. I’ve got the following contrived example, where I’m trying to assert the invariant of a try/get pattern that if it returns true then the out object is non-null, otherwise if it returns false.
public static bool TryParseFruit(string maybeFruit, out Fruit fruit)
{
Contract.Requires(maybeFruit != null);
Contract.Ensures((Contract.Result<bool>() && Contract.ValueAtReturn(out fruit) != null) ||
(!Contract.Result<bool>() && Contract.ValueAtReturn(out fruit) == null));
// Elided for brevity
if (ICanParseIt())
{
fruit = SomeNonNullValue;
return true;
}
else
{
fruit = null;
return false;
}
}
I don’t like the duplication inside Contract.Ensures so I wanted to factor out my own method for this.
[Pure]
public static bool Implies(bool a, bool b)
{
return (a && b) || (!a && !b);
}
Then I changed my invariant in TryParseFruit to
Contract.Ensures(Implies(Contract.Result<bool>(), Contract.ValueAtReturn(out fruit) != null);
But this generates warnings that the “ensures is unproven”. If I then perform the inline refactoring on my Implies method then everything is OK again.
Could someone explain to me why this happens? I’m guessing it’s because Contract.ValueAtReturn is used magically in some way that means I can’t just pass it’s result off to another function and expect it to work.
(Update #1)
I think that all of the following Contract.Ensures express the same thing (namely that if the function returns true then fruit is non-null, otherwise fruit is null). Note that I am only using one of these at a time 🙂
Contract.Ensures(Implies(Contract.Result<bool>(), Contract.ValueAtReturn(out fruit) != null));
Contract.Ensures(Contract.Result<bool>() == (Contract.ValueAtReturn(out fruit) != null));
Contract.Ensures(Contract.Result<bool>() ^ (Contract.ValueAtReturn(out fruit) == null));
However, none of the above Contract.Ensures lead to a clean compile of the code below. I want the Code.Contracts to express that fruit.Name cannot be a null reference.
Fruit fruit;
while (!TryGetExample.TryParseFruit(ReadLine(), out fruit))
{
Console.WriteLine("Try again...");
}
Console.WriteLine(fruit.Name);
I am only able to get the completely clean compile with code contracts if I use the long winded way of expressing this detailed above. My question is why!
Of course, you can also try
Contract.Ensures(Contract.Result<bool>() == (Contract.ValueAtReturn(out fruit) != null));I have a vague recollection that the analyzer prefers == to other operators.I’ve had some success tracing these things with
Contract.Assertwhich helps you find out where the hole in the analysis lies. I have also found cases whereContract.Assertallows the analysis to succeed. In other words, you might fix this with a couple of assertions:Messy, I know. On the other hand, if any assertion fails, you can look, for example, at other aspects of the logic. For example, you can litter your code with
Contract.Assert(SomeNonNullValue != null);to see where the analyzer is losing its certainty about the non-nullness ofSomeNonNullValue.EDIT
If the
Assertis unproven, but you know that it should be provable, then you can use that to help isolate the problem. I suspect that the problem (or at least part of it) is your lack ofEnsuresin theImpliesmethod. Try addingContract.Ensures(Contract.Result<bool>() == (Contract.OldValue(a) == Contract.OldValue(b)));Also, as I again have vague recollections about different handling for different logical operators, try restating the return of that method. For example:return a == b;