Why can’t NullReferenceException tell you the type of the instance that was null?


If you have done much managed development you have run into a NullReferenceException more times that you’d care to count.  The CLR throws this exception when you try to access instance state on null instance…


 


One of your internal customers suggested we give the type of instance that was null to help track down the errors.  Not a bad idea, but Chris Brumme made it clear this is harder than you might expect…


 


The NullReferenceException occurs because an instruction like “call [eax+44]” or “mov edx, [esi+24]” has resulted in an access violation.  We don’t retain nearly enough information to form a correspondence between a particular register being NULL at a particular EIP and the fact that a particular reference in the application was null.  Especially since the EIP might be in a shared helper like a write barrier routine or an array helper.  In those cases, we would have to perform a limited stack walk to get the effective EIP.


 


The machinery that would be required to improve this error message is huge.  For the foreseeable future, you will have to rely on debuggers, or on FX code explicitly checking and throwing an appropriate NullArgumentException.


 


 


Oh well, back to the debugger!


 


But this does raise a number of interesting questions….


 


1)       I said that we throw a NullReferenceException when you try to access instance “state” (eg a field).  What if you have an instance method that does not touch any instance state (for example an instance method that just does a Console.WriteLine (“hello“)).  Will you get a NullReferenceException when you call that?  Why?  Hint: It is one of those interesting differences between the CLR and the C# programming language. 


2)       As Chris implies above, the .NET Framework and WinFX generally do argument checking on all publicly exposed APIs.  I continue to think this is a good thing to help you track to errors, but we do pay a very small perf price for these… Are they worth it?


3)       Back in the day we had a number of long debates about the naming of NullReferenceException. As you VB folks know, there is no such this as Null in the VB world (expect maybe in the database)… VB uses the term “Nothing” for this concept.  In retrospect should we have called in “NullReferenceOrNothingException”?  Has anyone worked with a VB developer that was actually confused by this?


 


 


rewritting history here a little bit… I put “Empty” instead of “Nothing” when I first posted.  Thanks to those of you who pointed it out.

Comments (23)

  1. Martin Naughton says:

    Hi Brad,

    I don’t advocate the "NullReferenceOrEmptyException" approach myself.

    Otherwise, you’d have to extend the name for .NET COBOL developers etc., wouldn’t you?

    I think one, well-understood term should be used. The term "null" is the best one, in the general case, if you ask me. The fact that is also a keyword in some languages is a happy coincidence.

    Martin

    Incidentally, the equivalent of "null" in VB is "Nothing".

  2. Eric says:

    Null isn’t a completely foreign reference to most VB devs, I would think. For one thing, if you’ve ever called a Win32 or other C function from VB, you’ve probably encountered vbNullString. And any VB dev who has SQL experience should have encountered NULL in that context as well.

    And for those relatively (I hope) VB devs who have never used Win32, SQL, or learned any C-like language, picking up Null as an idiom for Nothing should be pretty easy anyway.

  3. Eric says:

    relatively *few*. Need more coffee…

  4. Jelle Druyts says:

    I can’t seem to get trackbacks working between DasBlog and .Text, I must be doing something wrong here. Anyway: I have an idea as to why it should be possible to call methods on null objects from the CLR point of view, but why it fails in C#:

    http://jelledruyts.homeip.net/PermaLink.aspx?guid=92a28981-949c-450c-b3d0-d40a4bf6277d

    Regarding the "NullReferenceOrEmptyException"-idea: please no. That just sounds awful, NullReferenceException is perfectly acceptable to me. The term "null" is and has been used for years to indicate a special place in memory, or a non-existant object, or a database row that has no data. "Emtpy" to me sounds like an existing object without any state (which could make sense sometimes).

  5. Tom McKearney says:

    Has anyone worked with a VB developer that was actually confused by this? I’ve worked with VB developers that get confused about LOTS of things… Never specifically this though 🙂

  6. joe says:

    VB develoeprs aren’t stupid. They can learn what the hell a NULL value is. If they can’t, well, they shouldn’t be writing software then, should the?

  7. Bob Ainsley says:

    No, as a VB developer, I don’t think the error message should have been called "…NullOrEmpty…". But then I’m one of those developers who thinks that the VB6 -> VB.Net ‘Cleanup’ didn’t go far enough. I hate seeing, "…static, or shared in VB.Net…" in the documentation. As the saying goes, "It’s the framework, stupid!" The closer my programming language resembles the framework, the less of a mind shift I have to go through when I’m switching between the two.

  8. Dmitriy Zaslavskiy says:

    I would argue for avoiding explicit check, and letting system throw an NullReference exception. Otherwise all those checks will addup to a lot of extra code, and performance is also important

  9. Duncan Smart says:

    VB calls null "Nothing" (not Empty – that was what an uninitialised Variant was called), so if anything a VB-er would expect a "NothingReferenceException"

  10. James Bellinger says:

    As far as #2 goes, PLEASE continue to do as much argument checking as possible. One of the most frustrating things about Win32 is that it lets you make mistakes that you don’t find out about until something else possibly even unrelated goes wrong. Further, if you don’t check all arguments, developers won’t catch bugs and your hands will be tied (relatively anyway) when making new versions of the API. Better to catch everything immediately. And not just in a ‘debug’ mode either, because one thing you find is that some developers are criminally incompetent and wouldn’t use a debug mode if their program ran fine in release but had errors in debug. Don’t allow their kind to sneak by.

  11. James Bellinger says:

    ‘A very small perf. price’ That’s another thing. It’s clear there isn’t a performance need by that statement. Don’t introduce chaos for a 5% speed-up. Moore’s Law will get you that in short order anyway, so it’s needless, but development time will definitely be slowed by more than that trying to figure out what on earth is going on..

  12. Jerry Pisk says:

    You run into this exception more than you care to count? You have got to be kidding Brad, maybe VB programmers do but anybody who ever worked with C/C++ knows to check their object references (pointers) before they use them. But CLR’s design guidelines actually make people use objects without checking if they have them, we’ve talked about this before (returning empty strings/arrays/collections versus returning nulls). And this is why I think that rule is just going to lead to worse code and you’re going to have to think about things like this.

  13. Corrado Cavalli says:

    >Has anyone worked with a VB developer that was actually confused by this?

    Never found one, many VB devs use both C# and VB so never found any problem with nullreference exception (indeed many warning and/or compiler messages reflects C# logic…).

  14. _ says:

    >> VB uses the term “Empty” for this concept.

    Actually, it uses Nothing. Empty is something quite different.

  15. Pavel Lebedinsky says:

    How does the CLR decide if a given AV should be converted to a NullReferenceException or not? Does it check that the referenced address was in fact 0? Does it look at the faulting instruction/address?

    I hope it does at least check the referenced address. I’d hate to debug a process where an AV resulting from memory corruption was converted to a managed exception and silently handled.

  16. Jelle Druyts says:

    Update: with a little help from Brad (and Don), I think I found the answer to his pop quiz 🙂

    http://jelledruyts.homeip.net/PermaLink.aspx?guid=92a28981-949c-450c-b3d0-d40a4bf6277d

  17. 2) yes.

    3) NullReferenceOrNothingException: unnecessary complexity.

    Please keep the naming conventions and design guidelines as simple as possible. Otherwise, they will be ignored, and your efforts are in vain.

  18. Mark Levison says:

    Absolutely – the small performance cost, saves me from far bigger problems on a regular basis. In addition its inspired our team to use arg checks throughout our code. They’ve never been a performance problem for us < 1% our time is spent doing arg checks.