Exceptions versus error return values

March 8, 2010

Python has two ways of signalling that a function has failed; you can raise an exception or return a special error value of some sort. I use both techniques in different circumstances; since I've recently been writing some Python code, I've been thinking about exactly what those circumstances are, as far as I can tell.

(Self-analysis is tricky given that I don't particularly think through the choice when I'm making it; I handle errors however seems right for the function I'm writing at the time.)

Generally, I tend to use error return values if I expect failure to be routine, especially if there is a natural return value that is easy for callers to use. For example, getting a list of IPv4 and IPv6 addresses for a host; it's routine to look up nonexistent names (or at least names with no IP addresses), and returning an empty list is an easy return value for callers to use (since in many cases they will just iterate through the list of IPs anyways).

I use exceptions if I expect failure to be rare, especially if there is nothing that the direct caller of a function is going to do to handle the problem. If the only thing that I'll do on failure is abort the program with a pretty error message, there's no need to complicate all of the code between the program's main routine and the failing function with code to check for and immediately return the error. (The obvious exception is if there is cleanup work to be done on the way out, but I've come up with ways to handle that, similar to phase tracking.)

I'm pretty sure that I'd use exceptions even for common failures if they had to be handled by someone other than the function's direct caller; I don't like cluttering functions up with a bunch of 'if error: return error' code.

This view is not the common Python one. As we can see from the standard library, the Pythonic way uses exceptions a lot more often than I do.

(I'd argue that this is a sensible tradeoff for a library, too. The advantage of exceptions is that they are unambiguous signals of failures that you can't possibly confuse with valid return values, and they force people using your library to explicitly deal with errors.)


Comments on this page:

From 82.132.139.153 at 2010-03-08 03:54:20:

A subroutine which is supposed to return a list of hostnames for an IP address hasn't failed if there are any, although it's close to the (a)buse of -1 as a return value for subroutines whose domain is positive integers (common in C and PHP).

I like Haskell's use of a 'Maybe' type for functions which might quite rightly not return a value. A 'Maybe' is either 'Nothing' or 'Just x', where x is the desired answer when there is one. The caller has to check and unpack the value if there is one. -- Jon

From 128.240.225.1 at 2010-03-08 08:35:01:

I wrote that last comment on my phone so it's not as legible as I would have liked :) I meant "hasn't failed if there aren't any" rather than are.

You could simulate the haskell "maybe" concept in C, but there's an awful lot of boilerplate:

#include <stdio.h>
enum maybeType { MAYBE_TYPE_NOTHING, MAYBE_TYPE_INT };
struct nothing {
 enum maybeType type;
};
struct justInt {
 enum maybeType type;
 int integer;
};
typedef union {
 enum maybeType type;
 struct justInt i;
 struct nothing n;
} maybeInt; 

void checkInt(maybeInt maybe) {
   switch(maybe.type) {
   case MAYBE_TYPE_INT:
       printf("it's an integer: %d\n", maybe.i.integer);
       break;
   default:
       printf("not an integer\n");
   }
}

int main() {
   maybeInt yesInt;
   maybeInt noInt;

   noInt.n.type = MAYBE_TYPE_NOTHING;
   yesInt.i.type = MAYBE_TYPE_INT;
   yesInt.i.integer = 42;

   checkInt(yesInt);
   checkInt(noInt);

   return 0;
}

It would be a lot shorter with some casts, but the point of the Maybe concept is to work with the type-system.

Written on 08 March 2010.
« Why I don't expect third-party support for OpenSolaris
How not to design an API (in C): the enum ordering mistake »

Page tools: View Source, View Normal.
Search:
Login: Password:

Last modified: Mon Mar 8 01:40:57 2010
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.