Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unproven Ensure that references another property in combination with an interface

Assume the following code:

[ContractClass(typeof(ICC4Contract))]
public interface ICC4
{
    bool IsFooSet { get; }
    string Foo { get; }
}

public class CC4 : ICC4
{
    private string _foo;

    public bool IsFooSet { get { return Foo != null; } }

    public string Foo { get { return _foo; } }
}

[ContractClassFor(typeof(ICC4))]
public abstract class ICC4Contract : ICC4
{
    public bool IsFooSet
    {
        get
        {
            Contract.Ensures((Contract.Result<bool>() && Foo != null)
                             || !Contract.Result<bool>());
            return false;
        }
    }

    public string Foo
    {
        get
        {
            Contract.Ensures((Contract.Result<string>() != null && IsFooSet)
                             || !IsFooSet);
            return null;
        }
    }
}

The contracts try to say:

  1. IsFooSet will return true if Foo is not null.
  2. Foo doesn't return null if IsFooSet returns true.

This almost works.
However, I get an "ensures unproven" on return _foo;, because the checker doesn't realize that Foo will always equal _foo.

Changing Foo to an automatic property with a private setter removes that warning, but I don't want to do that (I don't like automatic properties with private setters).

What do I have to change in the above code to make the warning go away while preserving the _foo field?

The following doesn't work:

  1. Changing IsFooSet to use _foo instead of Foo. It will result in an additional "ensures unproven" on IsFooSet.
  2. Adding an invariant Foo == _foo. This will result in an "invariant unproven" on the implicit, default constructor. Furthermore, on a real code-base the processing time of the static checker will be magnitudes higher.
  3. Adding Contract.Ensures(Contract.Result<string>() == _foo); to the getter of Foo as per this answer doesn't change anything.
like image 971
Daniel Hilgarth Avatar asked Feb 26 '13 13:02

Daniel Hilgarth


1 Answers

You can use short-circuiting to simplify the condition, and that works for some reason:

[ContractClassFor(typeof(ICC4))]
public abstract class ICC4Contract : ICC4
{
    public bool IsFooSet
    {
        get
        {
            Contract.Ensures(!Contract.Result<bool>() || Foo != null);
            return false;
        }
    }

    public string Foo
    {
        get
        {
            Contract.Ensures(!IsFooSet || Contract.Result<string>() != null);
            return null;
        }
    }
}
like image 88
Eli Arbel Avatar answered Oct 26 '22 13:10

Eli Arbel