Bill Blogs in C#

Bill Wagner discusses C#, LINQ, and other items of interest

Extension Methods and Null Arguments

A little while ago, I did a DNR TV on C# 3.0. During that, I talked about preserving null semantics when  you write extension methods.  I made the point that you should never test if the first parameter of an extension method is null. That’s because it breaks the semantics of member methods, which is what extension methods appear to be from the calling spot.

For example, this bit of code would throw a null reference exception:

 

SomeType foo = null;

foo.SomeMethod();

 

However, if SomeMethod were actually implemented like this you’d lose error information and let possible error conditions go undetected:

public static Result SomeMethod(this SomeType thing)

{

    if (thing == null)

        return null;

    // etc.

}

 

Clearly that’s bad.  Well, recently one of the folks like saw this DNR TV episode asked me this question:

What is your opinion of checking for null on the first parameter and then throwing an ArgumentNullException?

public static void SendMail(this IEnumerable<Person>

    sequence)
{
    if(sequence == null)
        throw new ArgumentNullException…;
}

That also changes the semantics of the method modulo an instance method. It is more subtle, but it has still changed.

As I said above, de-referencing null throws a NullReferenceException. the sample in the question above throws an ArgumentNullException.

That’s semantically different.

Client code that wants to examine and recover from that coding mistake will be broken. 

Important side bar point: I’m not advocating catching NullReferenceExceptions as a program logic technique (In fact, I think that’s a bad idea).

Even though I don’t want client developers to control program logic by chcking for NullReferenceException, I should ensure that my code obeys the existing semantics.

Well, suppose you changed the SendMail method as follows so it does follow the normal semantics:

public static void SendMail(this IEnumerable<Person>

    sequence)
{
    if(sequence == null)
        throw new NullReferenceException…;
}

Well, now it does obey the semantics of an instance method. That’s good.

However, you’ve now written extra lines of code that don’t do anything useful. If you removed the check, the code would behave exactly the same. As a general rule, I don’t like to write code that doesn’t do anything. (See gratuitous default constructors for an example). 

That’s why I make the practice of not checking null on the first parameter of extension methods.  I don’t write code, and it works correctly.

Published Sun, Oct 26 2008 1:00 PM by wwagner

Comments

# re: Extension Methods and Null Arguments@ Sunday, October 26, 2008 2:11 PM

I use ArgumentNullException and so should you, because:

1. Extension methods are only extension methods in languages that support them. They are otherwise simple static methods. Throwing a NullReferenceException has no value here.

2. NullReferenceException is a reserved exception for the CLR and should not be thrown manually. See the Framework Design Guidelines book.

3. Throwing should be as descriptive as possible. Throwing a NullReferenceException is not descriptive and simply means that somewhere in your code, you tried to dereference null. This looks like a bug in your code, rather than a legit exception.

4. You should never force the user to look into your code to understand why they're getting an exception.

Cheers,

Omer

# re: Extension Methods and Null Arguments@ Monday, October 27, 2008 3:38 PM

> Well, suppose you changed the SendMail method

> as follows so it does follow the normal semantics:

Your last code sample will throw the same exception but the stack trace will be different, right?

So it is not IDENTICAL.

by Blo

# re: Extension Methods and Null Arguments@ Monday, October 27, 2008 10:04 PM

Omer,  

I think we're actually pretty close to the same place.

1) I think I'm optimizing for those languages that support extension methods and you are optimizing for those languages that don't. I don't seen an answer that satisfies both of us, so let's agree to disagree.

2) We agree. Note that I said I would not include my own code to test and throw a NullReferenceException.  I would rely on the CLR to do that for me.

3) I see your point, from the view of languages that don't support extension methods.  Looking at it from the standpoint of extension methods, I would view it as a bug in the calling code. I think this s similar to 1)

4) I agree, and from the extension method syntax, I don't.  

Thank you for hte comment.

by wwagner

# re: Extension Methods and Null Arguments@ Tuesday, October 28, 2008 2:12 AM

re: #3, it's not about support of EM or lack thereof.

When I get a NullReferenceException, I look at the stack trace to see where it came from. The stack trace for your exception will come from within the call to the extension method, rather than from the call itself, requiring me to look into your method itself, thinking there's a bug there.