Returning None is Evil

Yes, that headline was written for dramatic effect. No, I don’t think that None itself is evil. Yes, I realize there are many cases where None is an appropriate return value. No, this post isn’t about those cases.

This is mostly a rant about Java, but the pitfall described below is definitely a potential problem in Python. I hope none of my fellow Djangonauts have fallen into this trap, but hopefully this post will help make sure it stays that way.

I work in Java during the day, and every day I run into the same error message, due to a popular Java philosophy: if a retrieval function can’t retrieve an appropriate object, it should return null. I don’t have any sources that support this being any kind of official stance by the Java folks, but I’ve seen it in plenty of Java code. This is the single greatest cause of the infamous NullPointerException. For reference, the Python equivalent of this typically looks like this (though there are variations):

AttributeError: 'NoneType' object has no attribute 'xxx'

Basically, you have some code that retrieves some data. It might get it from a database, a file, or some series of operations based on input data. Where it comes from doesn’t matter. What matters is what you do if you couldn’t get a proper value. In Java, code often returns null, which is allowed for most function definitions. This means that, even though something unexpected happened (data couldn’t be retrieved), your program continues merrily along without knowing about it.

That is, of course, until you try to use your shiny, newly-retrieved object. Java then falls over itself and dies a horrifically painful death upon realizing that you dared try to do anything with null. This is the NullPointerException, and it’s exceptionally (pun intended) difficult to track down. You see, the traceback only tells you where your code tried to reference some property or method of null. What you really want to find out is where did that null come from?

This generally requires firing up the code in a debug mode, where you can step through individual lines of code, inspecting what your mystery value contains at different points of execution. Then, once you finally find out where null is being returned, you have to figure out why a proper object couldn’t be returned, and fix that problem (which was left out of your traceback entirely).

Python, thankfully, takes a different approach. It’s so ingrained in Python philosophy that Tim Peters mentioned it in the 10th line of the Zen of Python:

Errors should never pass silently.

Essentially, that’s what happened: an error occurred. But the Java mindset is to ignore the real error and continue on anyway. I don’t know, maybe they feel that errors should only show up for catastrophic system failures, not normal every-day problems like an record not existing in a database. Even with that logic, why a NullPointerException in the wrong place is preferable to a RecordNotFoundError in the right place is beyond me.

If you’re using Python (which I hope you are), embrace exceptions. Raise them (or let them pass on their own, if they’re raised by code outside your control) whenever your code can’t do what it’s supposed to do.

I hope I’ve made the point well enough without writing a song called “Raise an Exception”. Whatever you do, don’t return None unless None represents some usefulness to your code. This isn’t usually the case, so you should generally avoid it unless you know you need it.

Disclaimer: In Python, functions that don’t explicitly return anything, automatically return None. This is fine, because external code won’t be storing that return value anyway, as long as you’ve made it clear that its return value is irrelevant.

Comments

  1. At 7:53 a.m. on Jan 21, 2007, Anonymous said ...

    pourquoi est-il impossible d'imprimer cette page proprement?

  2. At 10:24 p.m. on Nov 20, 2007, Steve L said ...

    But the Java mindset is to ignore the real error and continue on anyway ... etc.

    Sorry ... I think you're being a bit alarmist/holier-than-thou here.

    That is not the "Java mindset." If you return null, you're really supposed to check if the returned value is null and deal with it accordingly, or you can choose to throw an exception just like you would do anywhere else.

    Just because you find code/people who decide to return null and not check for it, I don't think it's fair to say that this is "the java way." It's not.

    While it's easy to use Java as a whipping post, it's not the language here, it's the programmer(s). Don't get me wrong, I like Python better than Java as well, but fair is fair...

  3. At 11:14 p.m. on Nov 20, 2007, Marty Alchin said ...

    Of course it's not a problem with Java as a language. Java itself has a very robust error system, which is to be applauded. The trick is, programmers of any language tend to influenced by philosophies for that language. It's just like we use "Pythonic" to describe adherence to a certain set of philosophies.

    My real issue here is something you mentioned, but glazed over.

    If you return null, you're really supposed to check if the returned value is null and deal with it accordingly, ...

    This assumes that you are in fact the same you in both sides of that equation. Unfortunately, many (probably most) programmers rely on third-party code. So I'm forced to use an if(obj != null) condition every time a get an object from a library. That shouldn't be my job.

    And yes, I understand that this may just be coming from my experiences with Python, but I've seen NullPointerExceptions crop up far too often among even the seasoned Java programmers I work with. Checking for null is something that you have to "deal with" when working with most Java code (note, I'm specifically saying Java code, not Java itself).

    So yes, you're right that it's the programmers at fault, not the language. But that's why I'm not advocating not to use Java, just not to return null (or None, as is more appropriate for my audience).

  4. At 5:01 a.m. on Nov 21, 2007, Simon said ...

    See http://www.c2.com/cgi/wiki?SamuraiPrinciple

    Cheers, Simon B. simon@brunningonline.net http://www.brunningonline.net/simon/blog/ GTalk: simon.brunning | MSN: small_values | Yahoo: smallvalues

  5. At 6:56 a.m. on Nov 21, 2007, Marty Alchin said ...

    Thanks for that link, Simon, that's exactly the kind of thing I was looking for.

  6. At 8:18 a.m. on Nov 21, 2007, GiacomoL said ...

    This sort of behaviour might be due to the fact that raising exceptions used to be fairly expensive (in terms of performance); so people preferred to introduce a few "if (obj != null)" in exchange for speed.

    This is probably not the case any more (especially not in Python, AFAIK).

  7. At 8:34 a.m. on Nov 21, 2007, Marty Alchin said ...

    Je blâme Blogger. Il sera meilleur bientôt, je promets.

  8. At 9:21 a.m. on Nov 21, 2007, Anonymous said ...

    On a side-note: What did bug me though, before I became a Python programmer, was that Python programs (much like Java programs) tend to 'crash' with obnoxiously long stack traces for things such as 'File not found' instead of a simple 'File not found'. I always have the tendency to catch all uncaught exceptions and only display the message (and then exit) unless we're running in some verbose mode. In that case, I display the whole exception including traces. But that always makes me feel unpythonic. Stuck between a rock and a hard place I guess.

  9. At 11:26 a.m. on Nov 21, 2007, Cedric said ...

    Hi Marty,

    There are so many things wrong with this post that I had to write a post myself to discuss them...

    http://beust.com/weblog/archives/000470.html

    Feel free to comment either there or here. And please, let's not turn this into a language war :-)

    -- Cedric

  10. At 11:40 a.m. on Nov 21, 2007, Marty Alchin said ...

    @Cedric: Well, "wrong" in this case is just as subjective as anything in my post, so we'll just agree to disagree. Sure, I generalized and exaggerated, but such is usually the case when dealing with personal opinions. I expect some people will disagree with me, and I make no apologize to those who do.

    Your response does raise some interesting points though, so I'll respond in more detail over there. And as I mentioned to Steve, I have no intention of turning this into a language war. The principle at issue here is actually language-agnostic. Anything that has return values and exception handling can hit this situation.

    But, you're right, I'm not going to make a religious war out of these philosophies. I've stated my opinion, you've stated yours. With any luck, we can learn from each other.

  11. At 11:42 a.m. on Nov 21, 2007, Michael said ...

    I've really enjoyed all of your excellent posts this month. Thank you so much.

  12. At 11:43 a.m. on Nov 21, 2007, Cedric said ...

    Absolutely, looking forward to a fruitful exchange.

    So tell me: are you saying that you return exceptions everywhere and that you never return None, or have you found a middleground that you didn't describe in this entry?

  13. At 12:56 p.m. on Nov 21, 2007, Marty Alchin said ...

    @Cedric: I'm writing a following today, and I'll try to explain myself in more detail this time. Thanks for the feedback!

Speak up!


This particular article was posted on Tuesday, November 20, 2007, and has received 13 comments.

I’ve posted a follow-up to this article, which better explains my position. I’m leaving this here, but make sure you read the newer one, and direct any comments there, if it leaves any questions unanswered.

It was preceeded by Understanding Middleware and followed by Except the Unexpected.

It contains the following links:

Archive

Categories

Powered by Django.