Monday, February 25, 2008

What is Null?

C# got null wrong.

I really like C#. I think it's one of the best things that Microsoft has ever done. The .NET Framework is also very solid. And Visual Studio is a mature, solid development environment. As a group, they make application development much easier.

But C# got a number of things wrong and one of those things, in particular, has been bugging me recently. Every object in the system inherits from the Object class and that means that you can count on all objects supporting a minimum set of methods. The minimum set is Equals, GetHashCode, GetType, ReferenceEquals, and ToString. Unfortunately, null is not an object, so null doesn't respond to any of these methods. This is most obvious with

which generates a runtime exception. Oddly,
if (null == null) ...
compiles and runs properly, but it shouldn't. Neither side of the comparison supports Equals. The compiler must special case this. There are other special cases as well. (string + null) and (null + string) both return the string.

But why doesn't null respond to ToString? The obvious answer is that it's not an object -- it's a special "magic" value. But magic values are almost never a good idea and I don't see why this case is an exception. The fact that null is a magic value is a compiler implementation detail which has nothing to do with how I want to use it as a programmer.

In recent languages, Ruby, which has plenty of flaws of its own, got this one right. Nil is a singleton instance of NilClass. But they also made a minor mistake. NilClass doesn't respond to the empty? method meaning that you can't use s.empty? unless you know for sure that the variable contains a string. Since Ruby's classes are open, I can fix this and I do (and don't worry -- there's plenty of time to talk about Ruby flaws in the future).

Can C# fix this? Well, there are some problems. If they just change it, any code that was written that relied upon the Exception being thrown will break. That wouldn't be good. But, it seems to me they could fix it by throwing the Exception anyway, then continuing on (and returning the empty string) if the Exception isn't caught. Since the uncaught exception would terminate the application, the worst that would happen is that some apps which would have crashed will keep going. They could do the same thing with the other Object methods as well.


Andrew M Greene said...

And the nullable types only make it worse.

Roy Leban said...

I agree.

Of course, the nullable types shouldn't exist the way they do. The boxable types were a mistake. Why should I have to care about the implementation detail that some types are implemented intrinsically?

When they did C# 2.0, they must have felt that they couldn't fix it by simply making all types nullable, so they added a way for us to explicitly declare nullability. When I use the nullable types, there are too many things that don't work (aside from ToString). For example, you can't pass an int? as an out or ref parameter to a method declared with an int (and there's no good reason in the case of an out parameter).

Post a Comment