Crazy Extension Methods Redux (with Oxygene)

Back in April I blogged about a crazy thing you can do with extension methods in C#3.0. At the time I was adamant that it was a bad idea. I still think it is a bad idea, however, my thoughts have evolved a little since then and I have, possibly a solution to my hesitance to use said crazy feature.

So, if you can’t be bothered to click the link, here is a quick recap. You can create an extension method and call it on a null reference and it will NOT throw a NullReferenceException like a real method call would. At the time I was saying it was not best practice because it breaks the semantics of the dot operator which is used for member access.

Last night, I attended an excellent talk by Barry Carr on Oxygene, an Object Pascal based language that targets the .NET Framework. Oxygene has a very interesting feature, it has a special operator for dealing with calls on a reference that might be null. If that language can do it, what’s so wrong with the functionality that Extension methods potentially give? Semantics. Notice that I said that Oxygene has “a special operator”. It doesn’t use the dot operator. The dot operator still breaks if the reference is null. It has a colon operator. In this case if the reference is null (or nil as it is called in Oxygene) then the call to the method doesn’t happen. No exception is thrown.

For example. Here is the code with the regular dot operator:

class method ConsoleApp.Main;
var
  myString: String := nil;
begin
  Console.WriteLine('The string length is {0}', myString.Length);
  Console.ReadLine();
end;

And the result is that the NullReferenceException is thrown:

NullReferenceException

Here is the code with the colon operator:

class method ConsoleApp.Main;
var
  myString: String := nil;
begin
  Console.WriteLine('The string length is {0}', myString:Length);
  Console.ReadLine();
end;

And the result is that the program works, it just didn’t call the property Length as there was nothing to call it on:

Result

At this point I really would like to show you what this looks like in Reflector to show you what is going on under the hood, however, I get a message that says “This item is obfuscated and can not be translated” and the code afterwards isn’t quite right. However, the crux of it is like this in C#:

int? length;

if (myString != null)

length = myString.Length;

Console.WriteLine(“The string length is {0}”, length);

Now, back to these extension methods. After seeing this I was thinking that perhaps my total unacceptablity of allowing a null reference to be used with an extension method was perhaps incorrect. In a normal situation with an accidental null reference exception being used the NullReferenceException wouldn’t be thrown at the point of the method call (after all, the null reference is actually being passed in as the first parameter in an extension method), but somewhere in the method itself. Normal good practice would place a guard block at the start of the method so that it would be caught immediately.

However, what if you wanted to create similar functionality to the colon operator in Oxygene and have it ignore the null reference and do nothing? Well, my advice would be to create a naming convention for your extension methods to show that null references will be ignored. That way you can get the functionality with a slight semantic fudge of the dot operator. Of course, you still have to do the work and set up guard blocks to handle the null situation yourself in the extension method.

Here’s an example:

class Program
{
    static void Main(string[] args)
    {
        string myString = null;
        Console.WriteLine("The string length is {0}", myString.NullableLength());
        Console.ReadLine();
    }
}

public static class MyExtensions
{
    public static int? NullableLength(this string target)
    {
        if (target == null)
            return null;
        return target.Length;
    }
}

2 Comments

  1. A little spice of generics and lambda would let you do:int? length = myString.Maybe(s => s.Length);Unfortunately, I can’t see a decent way to have it return a Nullable<T> or null without 2 different methods (MaybeValue and MaybeRef?).Or, you could call your extension method “_”, and it’s almost like a new operator. But, then we’re just starting to look like C++. ;)public static TValue? Maybe<TReference, TValue>(this TReference target, Func<TReference, TValue> operation) where TValue : struct where TReference : class { if (target == null) { return new Nullable<TValue>(); } return operation.Invoke(target); }

  2. Scott says:

    It sounds like what you’re describing is very close to “operator lifting”, which nullable types already do. The bottom line is that nullability (true nullability, not nullable types) is not really a first-class language citizen, which is what causes the “.” operator to throw NullReferenceExceptions. If nullability were a first-class citizen (and/or the . operator was lifted for all types) then callling a method on a null object would simply return null. In that case your example would simply work with calling myString.Length, which would return null.

Leave a Comment

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 )

Facebook photo

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

Connecting to %s