Monday, November 30, 2009

On Values And Options

Further thinking about the relationship between a Value and its related Option interface (what I was calling Ops) lead to the following construction rules:
  • A Value interface contains no methods
  • Storing a reference to an Option is fine, provided you can guarantee the reference is always non-null. If you can't guarantee this for some reason, declare a Value instead.
  • methods which return a reference to the Option interface must always return a non-null Option reference
  • Care should be taken not to store Options in ADT that have methods that can, under some circumstances, return null. For example, a map of type Map< ? , Value.Option> would not be safe since its get() method could return a null Value.Option reference under certain conditions.
  • Option references should never be declared as parameter types in method signatures
  • The methods on the Value interface inherited from java.lang.Object are @deprecated to warn the user they are calling the wrong interface
If an object stores a value object as a property of some container object, then one might expect to see a declaration like this:

class Container
{
    private Value.Option aProperty = Value.UNSPECIFIED;

    public Value.Option getProperty()
    {
        return aProperty;
    }

    public void setProperty(Value aValue)
    { 
        aProperty = Value.WITH.value(aValue);
    }
}

Where Value.WITH.value implements the catamorphism between Value and Value.Option.

The reasons for the asymmetry between the parameter type of the setter and the return type of the method are as follows:

  • As the consumer of a property, you don't want the hassle of applying a catamorphism to a return value before you can use it. It is reasonable for the method implementor to do this for you, and if the Option reference is the reference that is stored, it will, in any case, be trivial to do so
  • Given these construction rules, the only way to obtain a reference to an Option is to receive one from a method return or load one from a variable. If the Value -> Value.Option catamorphism and all other methods are guaranteed to never return null and you never initialize a Value.Option reference with null, there is no way you can receive a null Value.Option.
  • As the implementor of a class, you can guarantee by inspection that you never store or return a null Option. It is not possible for you, as an implementor, to guarantee that you will never receive a null Option-typed parameter from a caller. Type-safety will guarantee that you receive at least a Value. You can guarantee by construction that any Option reference derived from that value is not null. If you accept Option-typed parameters then you either have to assume that a caller will not make a mistake and pass a null or you have to apply a catamorphism to the parameter in order to restablish your certainity that it is not null. It seems simpler to re-use the Value -> Value.Option catamorphism in the setter method than to apply a second catamorphism to guard against the unlikely case that a caller has violated your method's contract.
  • Since the parameter type (Value) is different to the property declaration (Value.Option), type safety ensures that some kind of conversion will be applied to the parameter prior to it being stored. This prevents a lazy implementor of a setter method passing through a null reference to be stored in an Option-typed member variable.
  • Since returns typed with Value.Option are guaranteed by construction to be never null, even if the related value was null, there is no need for null checks in consuming code
  • The rules are simple to follow and unconditional in nature - any violations of these rules is a serious error and should be treated as such. There is no case for a storing or returning a null Option. Any such case is actually a case for passing or storing a null Value, which are the only safe types of reference to pass in this way.

0 Comments:

Post a Comment

<< Home