Question

I've managed to boil this down to the following test case but I'm wondering whether this is a limitation of the static checker in C# code contracts or something I'm missing. When I attempt to prove a contract using one style of code it throws an invariant unproven warning, yet (what I think is) an equivalent way of proving it works just fine.

Initially I thought this might be because I wasn't using an object with Pure properties (and therefore the code contracts couldn't assess whether the properties were deterministic) but creating a Pure wrapper around the object (happens to be Nullable<Int64>) didn't help.

Is there a difference between the first and third test cases, or am I correct in believing they are equivalent and it's just that the static checker can't evaluate the third case correctly?

//Works

private Int64? _violations = null;

[ContractInvariantMethod]
private void ObjectInvariant()
{
    Contract.Invariant(CheckIsValid(_violations));
}

[Pure]
public static Boolean CheckIsValid(Int64? value)
{
    return (value.HasValue ? value.Value >= 0 : true);
}

public Class1(Int64 violations)
{
    Contract.Requires(violations >= 0);
    Contract.Ensures(CheckIsValid(_violations));
    _violations = violations;
}


//Doesn't work, not provably deterministic

private Int64? _violations = null;

[ContractInvariantMethod]
private void ObjectInvariant()
{
    Contract.Invariant(_violations.HasValue ? _violations.Value >= 0 : true);
}

public Class1(Int64 violations)
{
    Contract.Requires(violations >= 0);
    Contract.Ensures(_violations.HasValue ? _violations.Value >= 0 : true);
    _violations = violations;
}

//Also doesn't work, even though it's provably deterministic

private PureNullableInt64 _violations = null; //A wrapper class around Int64? with [Pure] getters

[ContractInvariantMethod]
private void ObjectInvariant()
{
    Contract.Invariant(_violations.HasValue ? _violations.Value >= 0 : true);
}

public Class1(Int64 violations)
{
    Contract.Requires(violations >= 0);
    Contract.Ensures(_violations.HasValue ? _violations.Value >= 0 : true);
    _violations = violations;
}
Was it helpful?

Solution

All three versions are the same, your first version doesn't work either. It just looks like it does, because you have the warning level set low enough that the warning gets masked. Try setting the warning level to the highest and you'll see the "Ensures unproven" warning.

The issue is that there is no contract that says new Nullable<T>(x).Value == x. There's only a contract that says new Nullable<T>(x).HasValue. That's not sufficient to prove your invariant. There are many contracts that should be specified for the base classes but aren't yet. You can take this to the Code Contracts Forum and request an addition.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top