Alois Kraus

blog

  Home  |   Contact  |   Syndication    |   Login
  106 Posts | 8 Stories | 293 Comments | 162 Trackbacks

News



Article Categories

Archives

Post Categories

Image Galleries

Programming

I have written far too many null checks in my life. Why do we have even null values? They only seem to provoke a NullReferenceException in our code after all. F# for example has the option type with the value None which is semantically the same as null without being null which makes it impossible to access invalid values by accident. It is of course possible to create null values in F# but it is not the most natural thing in a functional programming language. How can we make C# safer without writing explicit if( xxx  != null ) … statements over and over again? One thing that comes to my mind would be to have a generalized null-coalescing operator (this is the ?? operator). Ian Griffiths has also a very interesting article about lifting the . operator to call the method only when the instance is not null by using sophisticated but not practical methods.  What was this feature anyway? Lets have a look at the following code:

                string ReadConfigValues(NameValueConfigurationCollection appSettings, string key)

        {

            string currentValue = "";

            if (appSettings != null && appSettings[key] != null)

            {

                currentValue = appSettings[key].Value ?? "";

            }

 

            return currentValue;

        }

My proposal at Connect is to enhance the syntax of method calls with the new .? (generalized null-coalescing) operator which calls a method only if the object reference is not null. That allows us to rewrite the previous code to

        string ReadConfigValuesBetter(NameValueConfigurationCollection  appSettings, string key)

        {

          return appSettings.?GetElementKey(key).?Value ?? "";

        }

That is much nicer and if you want to have it in a future C# version you can vote at Connect here. In the meantime I did explore a different strategy by using some extension methods to “automate” the null check

        string ReadConfigValuesUsingExtensionMethods(NameValueConfigurationCollection appSettings, string key)

        {

            string lret = "";

            appSettings.WhenNotNull(() =>

                appSettings[key].WhenNotNull( (cfgElement) =>

                    cfgElement.Value.WhenNotNull( () =>

                         lret = cfgElement.Value)));

            return lret;

 

        }

In this specific case I still prefer the explicit null  checks because they are easier to read and the lambda expression magic. It is cool to show off but I admit that is not really readable. But there are cases where the extension methods are useful if you have true object oriented code with some base and many child classes. There you need to cast quite frequently the base class to your desired child class and check if you were successful.

        class A { }

        class B : A { }

        class C : A { }

        class D : A { }

 

 

        void CastingMadness(A o)

        {

            B b = o as B;

            C c = o as C;

            D d = o as D;

            if (b != null)

            {

                Console.WriteLine("Got B");

            }

            else if (c != null)

            {

                Console.WriteLine("Got C");

            }

            else if (d != null)

            {

                Console.WriteLine("Got D");

            }

        }

 

        void CastingBetter(A o)

        {

            (o as B).WhenNotNull((b) => Console.WriteLine("Got B"));

            (o as C).WhenNotNull((c) => Console.WriteLine("Got C"));

            (o as D).WhenNotNull((d) => Console.WriteLine("Got D"));

        }

In this case the extension methods are far better than the null check approach. For nullable (struct) types I do also provide some extensions to get the same semantic.

    public static class Extension

    {

 

        public static bool WhenNotNull<T>(this T value, Action func) where T : class

        {

            if (value != null)

            {

                func();

                return true;

            }

 

            return false;

        }

 

        public static bool WhenNotNull<T>(this Nullable<T> value, Action func) where T : struct

        {

            if (value != null)

            {

                func();

                return true;

            }

            return false;

        }

 

        public static bool WhenNotNull<T>(this T value, Action<T> func) where T:class

        {

            if (value != null)

            {

                func(value);

                return true;

            }

 

            return false;

        }

 

        public static V WhenNotNull<T,V>(this T value, Func<V> func) where T : class where V:class

        {

            if( value != null )

            {

                return func();

            }

 

            return null;

        }

 

        public static V WhenNotNull<T, V>(this Nullable<T> value, Func<V> func)

            where T : struct

            where V : class

        {

            if (value != null)

            {

                return func();

            }

 

            return null;

        }

 

        public static V WhenNotNullS<T, V>(this Nullable<T> value, Func<V> func)

            where T : struct

            where V : struct

        {

            if (value != null)

            {

                return func();

            }

 

            return default(V);

        }

 

        static public void ForNotNull<T>(this IEnumerable<T> list, Action<T> func) where T : class

        {

            if (list == null)

                return;

 

            foreach (var v in list)

            {

                if (v != null)

                    func(v);

            }

        }

 

        static public void ForNotNull<T>(this IEnumerable list, Action<T> func) where T : class

        {

            if (list == null)

                return;

 

            foreach (var v in list)

            {

                T castedValue = (T)v;

                func(castedValue);

            }

        }

    }

Please do not use this code to skip the initial null check and swallow all possible errors of your API. Normally throwing an exception is the best approach. But if you read data from external sources like disc/network you can have to be able to process the incoming data reliable even if some inputs might be not valid. There is a tradeoff between being silent about errors and throwing an exception for every detected non conformity. An application has to be robust (swallow minor errors) but also correct (stop processing by throwing an exception). The only way to find out is to test and to use some null checks before bad things happen. But be warned that adding additional checks might lead to new bugs that were not possible before. Do you know how many races you can get if you add to your event handler a null check before calling it? If you make your event calling code thread safe you enable the previously not possible race condition that you call an object which has already unsubscribed from your event.

posted on Sunday, November 22, 2009 5:20 PM

Feedback

# re: Automatic Null Checks 11/30/2009 3:42 AM rowan
"method calls with the new .? (generalized null-coalescing) operator"

shouldn't that be "?."?

# re: Automatic Null Checks 11/30/2009 4:11 PM Alois Kraus
My opinion is that an operator should be read from left to right. First comes the . to indicate a method call then the specialization to a null checked method call. This is at least the way I would read this. There are of course different options. What would be your selling point for the ?. operator?

Yours,
Alois Kraus


# re: Automatic Null Checks 12/1/2009 12:23 AM rowan
I don't have a preference, in your text you say ".?" but in your code example you have "?.", I just assumed the code to be correct.

# re: Automatic Null Checks 12/3/2009 10:24 AM Alois Kraus
uups sorry I have updated the code sample.

# re: Automatic Null Checks 1/12/2010 11:51 PM Avdhut
i suppose i would like to go with "?." operator in place of ".?"... the "?" in former case will be more associated with the object than the function call... as wht i would expect after the "." operator are the members of the class... the "?" mark will indicate the object is null and so would prefer if it could stick to the object itself than the class member

Post A Comment
Title:
Name:
Email:
Comment:
Verification: