0

I have a class which allows a switch-like statement using any object type T and allows specifying a return type R. When I try to require non-null values I receive a warning that it requires unproven: value != null. Figured an Assume would take away the warning of the static checker but enforce it in runtime, but it does not do the former. What are my options?

Here is the class with the Contract.Requires statement:

public class SwitchReturn<T, R>
{
    public SwitchReturn(T o)
    {
        Contract.Requires(o != null);

        Object = o;
    }

    public T Object { get; private set; }
    public bool HasValue { get; private set; }
    public R Value { get; private set; }

    public void Set(R value)
    {
        Contract.Requires(value != null); // <== the source of all the troubles

        Value = value;
        HasValue = true;
    }
}

Here is an example of calling code with an unproven requires:

public static SwitchReturn<T, R> Case<T, R>(this SwitchReturn<T, R> s, Func<T, R> f)
{
    Contract.Requires(s != null);
    Contract.Requires(s.Object != null);
    Contract.Requires(f != null);

    if (!s.HasValue)
    {
        Contract.Assume(f(s.Object) != null); // <== does not remove the warning
        s.Set(f(s.Object)); // <== this is the cause of the warning
    }

    return s;
}

I would not want to remove the non-null requirement. Can a constraint be placed on the FUNC parameter that it ensures it does not return nulls?

Keith
  • 20,636
  • 11
  • 84
  • 125
Stefan de Kok
  • 2,018
  • 2
  • 15
  • 19

2 Answers2

1

f is not known to be pure. Calling it twice may give different results, so assuming that the first result is non-null says nothing about the second result.

You should be able to store the result in a variable, add an assumption about that variable, and then pass that to your other method.

if (!s.HasValue)
{
    var val = f(s.Object);
    Contract.Assume(val != null);
    s.Set(val);
}
0

It sounds like the cause of the problem is that T and R may be value types. The null check would fail in that case.

The solution is to use type constraints to require T and R to be reference types.

public class SwitchReturn<T, R>
   where T : class
   where R : class
{
   ...
}
Keith
  • 20,636
  • 11
  • 84
  • 125
  • 1
    The null check would not fail for value types: the comparison to null would be valid, and it would always determine that the value is not equal to null. –  Dec 31 '14 at 17:18