Adversus Nullus, Unnullable<T>

Let’s fix C.A.R. Hoare‘s billion dollar mistake for C#: Null-pointer dereferences. – Isn’t hindsight great?

By default, C# reference types are nullable, meaning one can assign a null value to a variable of a reference type. These null values can propagate away from the point of origin and spread terror and havoc. There is a good and sound principle in software engineering that says: fail early, fail often. This means that a program should detect or exhibit a software defect right where it occurs (which is as soon as it occurs; well possibly sooner using static analysis and symbolic execution) and it should exibit a predictable behavior towards it, failing each time, reflexively. A program that just carries on can end up making much more damage along the way and can be harder to debug.

Then of course we might choose to interpret what we mean by “fail”. It might be a brutal failure or a recovered failure. The base philosophy has to be that the defect is at least signalled at its origin, handled or not.

One approach to dealing with this issue is using contracts. One can annotate function and method definitions with pre- and post-conditions expressing that the input and output of a piece of code will not and must not accept or deliver a null value. If spread everywhere, this will help catch the error where it occurs. It’s like a finely masked web spread out over the code, which will not allow a null value much freedom to move around before it is caught: thus enforcing the fail fast principle.

In Microsoft .Net, traditionally, there has not been support for contract programming or what is known as Design by Contract from Eiffel. People can write their own assert functions and sprinkle them all over the place which may help but it is not a very good contract solution. Things improve in .Net 4.0 with language-agnostic contract support.

A different approach is to have types help out.

In software engineering we face the same problem over and over again: in an imperative world it used to be fine to have object be mutable by default. In the new manycore world this approach is untennable. Similarly, in the past, it used to be (somewhat) ok to have reference types include null in the domain. It just turns out that in practice this was a really bad mistake. Null-pointer exceptions én masse. In the first case a paradigm shift forces us to change strategy, at least gradually. In the second, a painful history of bugs teaches us better ways.

As an aside, recently Dr. Erik Meijer and team have dualized the IEnumerable/IEnumerator types, creating the quite beautiful IObservable/IObserver types. In other words, the two type sets form eachothers duals. That is not to say that the former is no longer needed but it’s one more example of dualization. Mutable vs Immutable another (well an opposite at least).

New since, what, .Net 2.0 is Nullable<T>. This type allows us to define primitive (struct) types as nullable by wrapping them in another type that signal whether the wrapped value is actually null. It will not work for classes since they are already nullable and the Nullable type is defined to only work for T where T is a struct type.

The obvious thought here is: OK, we had integers that we needed to be nullable. Now we have objects that we need not to be nullable. Let’s “dualize” this. And so I made a simple struct to demonstrate the idea. This would benefit from language support but can really help out on its own. The Nullable<T> type has syntactic support in C# via the T? notation.

The definition is as follows.

public struct Unnullable<T> where T : class
{
    public Unnullable(T x)
    {
        if (x == null)
            throw new NullReferenceException();
        item = x;
    }

    public T Item
    {
        get
        {
            return item;
        }
    }

    private readonly T item;
}

I made it up an early morning, after waking up far far too early and it has to be tested out thouroughly. But just quickly trying some obvious null assignments fails. Even not assigning a value to a newly declared Unnullable<T> variable will fail at compile-time; well, even before, as Intellisense and background compilation will warn you before you run a regular compile. At least if you use Visual Studio.

It’s impossible to construct an Unnullable that contains a null. So it really is un-nullable. At least if not resorting to evil means such as reflection. If this type is used, whereever it is used it will provide null-safety, i.e. non-nullness.

In a not too distant future we may see this built into C# and VB, maybe even on the class level where we can say that a class is unnullable by design. This may create other problems that we’ll defer indefinitely – for now.

2011-02-11 note: we could also combine Code Contracts with this design this way:

public struct Unnullable<T> where T : class
{
    public Unnullable(T x)
    {
        Contract.Requires(x != null);
        item = x;
    }

    public T Item
    {
        get
        {
            return item;
        }
    }

    private readonly T item;
}

References

A Channel 9 thread on ideas for C# 5.0

Advertisements

About xosfaere

Software Developer
This entry was posted in Computer Science, Declarative, Imperative, Paradigm, Software and tagged , , , , , , , , , , , , , . Bookmark the permalink.

2 Responses to Adversus Nullus, Unnullable<T>

  1. Ryan Riley says:

    Looks like a terrific idea to me. I was thinking maybe instead of throwing an exception, you could just return the default value… except in the case of reference types, that would be null. So nevermind. 🙂

  2. xosfaere says:

    That’s right. It makes quite good sense to throw that exception, that means at the very instant you try to initialize with a null, you get an exception, not after, not somewhere deep in the call stack. If the exception were to be a checked exception, the client would have no choice but to handle the exception which would probably make him think twice about this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s