Exceptions or return values?
August 10, 2006 8:13 PM   Subscribe

Exceptions or return values, and why?
posted by knave to Computers & Internet (20 answers total) 1 user marked this as a favorite
Wow, that was a generic question.

Functions return values. An exception can be a return value, typically false.
posted by SpecialK at 8:18 PM on August 10, 2006

(It will vary greatly depending on your language choice about what you'll call exceptions or return values as well. For instance, many languages have an exception datatype or construct that you can test for. Many others don't. Therefore, in languages that don't, you'll never return an exception, but you will return a value that indicates an exception happened or test for an expected resolution ... i.e. function returns an int, 1, if the operation was successful and a string indicating what happened if the operation failed or otherwise threw an exception. That's bad design IMHO, but I do see it a lot in some languages.

Why your question was bad is that you provided no context. What other design considerations are going in here, including the language you're working in?)
posted by SpecialK at 8:22 PM on August 10, 2006

A return value is the normal happy-path result from a method. An exception is anything else. For example:


In the above example, what happens when there is no user with the Id "12345"?

An exception is a non-happy-path result. It's a way to setup an explicit contract indicating particular falure scenerios. Often times an exception will carry additional context indicating the cause of the problem. Most languages that support exceptions will either make you aware of the exceptions that can be thrown for a given method (C#, kinda), or they may even go so far as to force you to handle them (non runtime exceptions in java, and C++ too I think). I'm sure there are many more languages that support exceptions, I'm just not sure what they are...

Additionally, exceptions often carry additional information with them making debuging easier. Where in the code the exception was thrown is called a stack trace.

Another better example would be a method called authorize. authorize would take a user id and an operation. (in java, cause It's what I know best):

public void authorize(String userId, String operationName) throws NoSuchUserException, NoSuchOperationException, AuthorizationFailedException {

You can tell just by looking at the above code block what the possible results are for the method authorize(...) ... And in this (somewhat rare) instance, the happy path requires no data, so there method is void.

Runtime exceptions in Java don't have to be caught and are generally considered system-level exceptions, meaning if I call a method and it throws a runtime exception, there's little I can do about it so I shouldn't be forced to handle it. An example of a runtime exception might be something like NullPointerException when you try to dereference a null object. Runtime exceptions indicate a failure at the system level which is generally unrecoverable. I'm reminded of the old programming mantra "Don't check for an error you don't know how to handle" ...

Anyway, hope that helped and didn't just confuse for further :)...
posted by crunchyk9 at 8:49 PM on August 10, 2006

Here is Joel Spolsky's take on the matter.
posted by Rhomboid at 9:06 PM on August 10, 2006

This question needs clarification.

Still, one day you might be tempted to use exception macros in C using longjmp. Don't do it. Just use return values.
posted by cmonkey at 9:07 PM on August 10, 2006

Throwing an exception is more expensive than just returning a value: computationally, in terms of code clarity, and in terms of ease of recovering from. Therefore, don't use exceptions for things that you expect to occur in a normal execution sequence.

If you're doing something like

try {
} catch (ExceptionItThrows)

then you're probably not using exceptions well.

(On preview: Joel is normally pretty insightful, but this article about exceptions is not one of his better ones.)
posted by inkyz at 9:14 PM on August 10, 2006 [1 favorite]

Response by poster: The question is really straightforward. For error handling, which do you feel is best, exceptions or return values? If you aren't sure what that means, you probably shouldn't try to answer.

I'm talking about languages that have exceptions, obviously, like Java and C++.

I've seen the Joel article, as well as this one, which disagrees with Joel. I'm trying to get a more general sense of what people think is appropriate.
posted by knave at 9:23 PM on August 10, 2006

Exceptions should be exceptional. Meaning something you're not expecting and haven't dealt with. Use return values, but be prepared to handle the unknowns (aka exceptions).
posted by blue_beetle at 9:23 PM on August 10, 2006 [1 favorite]

Response by poster: For error handling, which do you feel is best, exceptions or return values?
posted by knave at 9:27 PM on August 10, 2006

Exceptions tend to make code paths non-obvious. Stick with rvalues unless you have a situation where doing so would make your code unwieldy (I've never seen one of these in the real world, but they may be common in application domains unfamiliar to me).
posted by hamhed at 10:01 PM on August 10, 2006

One or the other, not both. Choose early.
posted by flabdablet at 10:29 PM on August 10, 2006

For all these people saying "stick with rvalues", let's consider an example. Suppose I want to write a function called ReadConfiguration which opens an XML formatted file, parses it, validates the values, and returns the configuration. Ohh yeah... in this era of internationalization, I want to return something that can be localized (as best as is possible, that is).

In C I'm probably use stdio, expat, and my own code. But how do I handle these exception cases: the file is missing, it isn't valid XML, and the data is invalid? fopen() has it's own set of error codes, expat another, and my code a third. How do I possibly merge them so that I can return a meaningful value?

One way that pops into mind is to allocate thread local storage for the error information. So if it's a problem in stdio I return MY_ERROR_STDIO, expat gets MY_ERROR_EXPAT, everything else is MY_ERROR and the user can call MyGetLastError to find out the specific information.

In Objective-C I'm probably using NSXMLParser and my own code. NSXMLParser will return an NSError and for myself I'll subclass NSError to provide information. So ReadConfiguration now returns YES/NO with an optional NSError parameter to get the extended information. Better.

In Java I'll be using JSAX and my own code. I'll have to subclass Exception, but I don't have to worry at all about the JSAX exceptions. And consequently, whoever calls ReadConfiguration gets the same option of either handling the exceptions or passing them on. Personally, I think this is best.
posted by sbutler at 10:38 PM on August 10, 2006

Expanding a little: error handling is the second most bug-inducing part of any design process (the first is any logic that deals with dates and times). If error handling is done thoroughly, it makes code verbose. If it's not, it turns code unreliable.

So if your project is mission-critical, and you have enough design time to get it right: handle error conditions explicitly via function return codes, and allow your code to reflect all the explicit error-handling decisions designed into it.

If you're whipping up a quick piece of shit to deal with some pressing issue, use exceptions.

Do not, under any circumstances, allow a quickly whipped up piece of shit to turn into a component of something you'll seriously rely on.
posted by flabdablet at 10:44 PM on August 10, 2006

It also depends on your language. I find that exceptions are more useful in Java, because the language forces you to think about exception handling more. If your method throws KnaveException, your know that the caller (or the caller's caller, etc) will handle it somewhere. Also, the finally clause ensures that cleanup is done, no matter how the function exits.
In C++ exceptions are less useful. It is easy to make a mistake and forget to catch them properly, and the lack of finally is a real pain. I almost never use exceptions in C++ code, except to maybe throw an unrecoverable error all the way back up to the main loop so that the program can die cleanly.
posted by AndrewStephens at 1:18 AM on August 11, 2006

For error handling, which do you feel is best, exceptions or return values?

It really depends. For simple cases? Return values. For more complex cases, where you need an error context? Exceptions. There's a reason that exceptions exist, and that's because they can be handy. But you don't need to go batshitinsane with them.

Having said that, I still feel this is a bad question. I never thought I would classify a programming question as chatfilter, but this is as close as I've ever seen.
posted by antifuse at 4:08 AM on August 11, 2006

It depends on your layer of abstraction.

Typically my lowest level code never throws and instead returns a result code of some kind. This is code that may or may not be written in a language that supports exceptions.

My middle level code calls the lower level code and may decide, on an error code to try different approaches or to suppress the error(s). Otherwise, it will translate the error code into something more meaningful for the context and throw.

The high level code ends up being the simplest in that it will probably run the middle level code in try { } blocks and either handle or pass on the exception with even more context.

The highest level code (if any) has the UI exception handler and uses the high level code.
posted by plinth at 7:32 AM on August 11, 2006

Exceptions for error handling, if it's a real error. If it's a situation where you get no results, I don't consider it an error.

We had a situation in a (Java) application where one consultant was adamant about exceptions to the point of being ridiculous. I think the key is to just be consistent within your application. If, for instance, you are doing some sort of call to get user information, I can see where either returning a null or an exception could work. You're going to fail quickly if the user doesn't exist, and probably create a new one.

However, if you're doing a search, I could see lots of possibilities -- I've seen good code that returns null, throws an exception, or returns an empty object. The last works pretty well because you don't have to check if the object exists before iterating.

This does border on chatfilter because it doesn't reference a specific situation. The answer is really "it depends."
posted by mikeh at 7:35 AM on August 11, 2006

AndrewStephens writes "In C++ exceptions are less useful. It is easy to make a mistake and forget to catch them properly, and the lack of finally is a real pain. "

C++ doesn't need finally; finally is a Java work-around because Java doesn't have destructors. In C++, throwing an exception causes local objects' destructors to be called. This is better than finally, because you don't need to explicitly add finally code.

And it's possible to catch all exceptions in C++ by using the
catch( ... ) construct.
In your own code, derive all exceptions from std:exception or a class derived from std:exception.

To answer the OP: Throw exceptions only in exceptional cases, when something happens that the current function simply has no way to handle itself. Throwing allows each higher-level caller an opportunity to handle the exception if it can.
posted by orthogonality at 7:54 AM on August 11, 2006

return codes, mainly for the reasons that Joel states.

I've had cases where i wanted more information, so i've created a global list of errors and got more information via GetLastError() or somesuch. But then again, i've been having to write a lot of C code lately.
posted by escher at 10:42 AM on August 11, 2006

orthogonality wrote:
C++ doesn't need finally; finally is a Java work-around because Java doesn't have destructors. In C++, throwing an exception causes local objects' destructors to be called. This is better than finally, because you don't need to explicitly add finally code.
True, but then you have to wrap every little thing you need cleaned up in a class. It may be good style to do this anyway, but I have rarely seen C++ code that does it properly.

Anyway, this is not a discussion about languages and I agree 100% with your answer to the OP.
posted by AndrewStephens at 1:38 AM on August 12, 2006

« Older 420 in Vancouver   |   Looking for a good pediatrician in Baltimore! Newer »
This thread is closed to new comments.