Microsoft just completed a DCR (Design Change Request) that rippled through the entirety of .NET 2.0 and will be available in the August CTP. They made Nullables truly null! Why is this a big deal? Consider the following C# code snippet running under Beta 2:

static bool IsNull<T>(T val) {
   return val == null;

static void Main() {
   object obj = null;
   Console.WriteLine(“obj is null: {0}”, IsNull(obj)); // Writes “obj is null: True”
   int? i = null;
   Console.WriteLine(“i is null: {0}”, i == null); // Writes “i is null: True”
   Console.WriteLine(“i is null: {0}”, IsNull(i)); // Writes “i is null: False”!

What the heck??? I just assigned i the value of null, a direct check confirms that it is null, but my generic method says otherwise. How can this happen? Let’s look at what is actually happening. An int? (which is just syntactic sugar for Nullable<int>) is a value-type. So when we call the generic method, our int? gets boxed. The box around the null definitely exists, which is what val == null is looking at in the generic method. Hence it returns false because the box exists, even though the value in the box is null. When you look at the code though, you don’t expect that. You expect to be examining the value.

The change in the August CTP makes the generic method work as expected for Nullable types, but it required making some fundamental changes to the CLR. Nullables are now intrinsic types and have special rules around how the runtime handles them. For instance, when boxing an int? which is null, a null is put on the heap, not a box containing null. Hence the above code works. You can also unbox any value-type into its Nullable equivalent. From Soma’s blog:

int x = 10;
object y = x;
int? z = (int?)y;   // In Beta 2, this throws an invalid cast exception at runtime  – not pretty

I wanted to say a big thanks to everyone at Microsoft who was involved in this change. It’s always gutwrenching to make such a sweeping change so close to shipping. I can only imagine the person-hours worth of testing that has been required to ensure that this change does not break existing code. Personally I think it’s definitely worth it. Frameworks and languages are easier to use the less baggage you have to carry around in your head. It’s great when things just work. This is an example of having your framework/language match the mental map you have in your head of how the world should work.

You can find some great information about this change on Somasegar’s and Joe Duffy’s blogs.