Code defensively, strengthen your design, use Fortis!

Introduction to Fortis C#

24 Jul 2015

My inspiration for this library and the series of blog posts that will accompany it, might be described as this: I have a slight love-hate relationship with C#. There are many things I love about it, but there are also a couple things that I think can do with more love. Fortunately we can design around some of the 'bad' features and increase the love. This blog will show you how!

Prerequisites

Lets begin

Avoiding the billion dollar mistake

In 1969 Tony Hoare was designing the type system for the Algol W Object Oriented language. He recalls:

"My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."

Nearly every object oriented language to follow has copied this design flaw, and whether we are used to dealing with it or not, nulls effect us in a negative way. When attempting to write a robust and error free program, the C# compiler does not aide us in finding references to variables, which at runtime, may evaluate to null! So what should we do? Avoid using nulls!!!

You can model your application is such a manner that the absence of data is represented by a specific type rather than the typeless null.

Consider this code:

Person GetPersonByIdNumber(string idNumber)
{
    // Implementation ommitted!
}

void Main(object[] args)
{
    // Print the persons name to the console
    var p = GetPersonByIdNumber("7910156517081");
    Console.WriteLine(String.Format("FirstName: {0}, Surname:{1}", p.FirstName, p.Surname);
}

Should we be checking whether the result of GetPersonByIdNumber is null before using it? Without knowledge of the implementation of the function we're calling, we do not know how it handles an error condition, it could return a null or it could throw an exception. The signature of the function offers no guidance in this case!

What about this code?

Nullable<int> ConvertToInt(string s)
{
    // Implementation ommitted!
}

void Main(object[] args)
{
    var p = ConvertToInt("bla");

    // Print the result to the console
    Console.WriteLine(p.Value);
}

Does the call to Console.WriteLine(p.Value) cause an exception? Yes it does, it suffers from a poor design. Exceptions are meant to be used for the Truly Exceptional conditions that arise, like when memory can't be allocated! There would be little point in catching a OutOfMemoryException, what could you do to correct the situation? But here accessing p.Value throws an exception, a situation that could be avoided entirely with the correct design!

Let's create our own types to model the absence and presence of values:

abstract class Option<T>;
{
    public sealed class None // Represents an absent value.
    {
    }

    public sealed class Some // Wraps a value when it is present.
    {
        public T Value
        {
            get;
            private set;
        }

        public Some(T value)
        {
            this.Value = value;
        }
    }
}

Now lets see how we could use this in an improved design:

Option<int> ConvertToInt(string s)
{
    // Implementation omitted!
}

void Main(object[] args)
{
    var p = ConvertToInt("bla");
    var someP = p as Option<int>.Some;
    if (someP == null)
    {
        Console.WriteLine("Couldn't convert to int");
    }
    else 
    {
        Console.WriteLine(someP.Value);
    }
}

Now you may say that we could have added a similar check earlier when dealing with Nullable<int> to prevent an exception, the difference here is, access to Value can only be achieved by casting to Option<int>.Some. We now have the assistance of the type system and unlike Nullable<int>, Option<int> can contain any value, not just value types like int!

If you've been watching carefully though, you may note that we have simply deferred the null issue! Nothing prevents us from constructing an instance of Option<string>.Some with a null value for instance. This is where Code Contracts come in handy.

If you have already installed Microsoft Code Contracts, you can make the following simple change to the constructor for Option<T>.Some:

public sealed class Some // Wraps a value when it is present.
{
    public T Value
    {
        get;
        private set;
    }

    public Some(T value)
    {
        // Tell code contracts to ensure that the value will never be null!
        Contract.Requires(value != null); 
        this.Value = value;
    }
}

Code Contracts will now ensure that callers never create an instance of Option<T>.Some with a null value! You've seen how we can avoid the Billion Dollar Mistake, but it may seem like a lot of effort, how can it be made easier?

The Fortis.CSharp library

The Option<T> class as introduced earlier along with Code Contracts solves the Billion Dollar Mistake, but there are many other desirable features that could be added. What about:

The Option<T> type available in the Nuget package package has the above mentioned features as well as others which will be discussed in future posts.

Please give it a try, and lets make programming in C# more fun and less error prone.

Tweet