Methods can go wrong. Problems can occur during the processing of a method that can result in either incorrect, or partial processing.
In many programs people choose to return an error value from their methods if processing doesn't complete, or completes incorrectly. The problem with this is that you cannot ensure that the caller checks it.
Another problem is that this prevents you from returning something more interesting, like the function result.
In some languages you can pass in a parameter to be filled with the (possible) error value. However this can be syntactically nasty and messes up the caller (who now has to allocate the object). Either way seems to make for more complicated code rather than less, and it becomes harder to separate out the error handling.
Use Exceptions to represent the possible exceptional conditions that can go wrong.
Counter-view to AvoidExceptionsWheneverPossible
I was a C programmer in a previous life. It was my job to implement an exception mechanism so that the bugs which were causing things to fail could be reported back to the user. In C, this was a totally horrendous task - I created a Context struct which was passed into every operation and almost always had to be checked afterwards. It was ugly, but necessary.
One of the problems was sometimes people didn't check for and consequently handle exceptions, so they would pass their context into some routine which did some operation, checked for an exception, and would find the exception that had been passed in. Consequently the routine would throw an exception, but the information about the exception was that the routine failed because of some completely unrelated earlier error.
My boss got really annoyed at this, because his coding style was to write only the straight line and not worry about things going wrong.
He demanded to know how to clear the exception from the context so that the second routine would succeed. I refused to tell him, of course.
I explained that if there was an exception already there, there was no point calling the second routine because things had already gone wrong. He couldn't accept that as an answer, so we didn't talk to each other for a week. Eventually he called me back to look at a problem, and said "I'm doing it YOUR way now, so why is this happening?"
OK, so I won the argument, but the fact that the correct way of using the exception mechanism became known as MY way disturbs me. If I hadn't dug my heels in, that code would still be happily throwing an exception which was then cleared and ignored. That experience taught me that sometimes you just have to force people to deal with exceptional situations. Yes they are a pain to deal with and make your code hard to read, but sometimes to get people to hold the nail still you just have to start hammering their fingers.
[discussion moved to SmalltalkAndExceptions]
Lately I've been working with the idea of using exceptions in Java to complement a sort of design by contract. Given a method
Result doSomething(Object aParam, Object anotherParam)
define the acceptable inputs for aParam and anotherParam (javadoc comments are good for this) and the allowable/expected results. If for some reason the method can't fulfill the contract -- either the params are out of range of it cannot compute the result for any condition -- then throw an appropriate exception, which may indicated an illegal argument or an abstraction of the context of the underlying failure.
If the method's contract says that it always returns a valid Result object then you never have to check the return value, just handle the exception. Your straight-line code is cleaner because you know the contract was fulfilled if the method returned OK, and your exception code handles all error conditions, or wraps and re-throws the exception if there is insufficient context to recover. (This sounds like the SamuraiPrinciple)
The Java collections framework demonstrates that idea. The documentation specifies exceptions for all kinds of situations one might encounter when trying to implement some specialized collection class, say a class implementing the Map interface on top of a database table that stores only strings of limited length.
Nested exceptions are great for this because you can catch any exceptions you don't generate and wrap the message/stack trace in your own exception, which you can handle at some point in your code when you have sufficient context to attempt recovery. Too much simple wrapping and re-throwing can lead to the ExceptionFunnel AntiPattern
. Be sure to have a real exception handling strategy in place.
The only alternative I know of to exceptions is to wrap every function in an if statement and either return with an error code or completely exit the program. The result is code whose purpose is more focussed on returning error codes than performing its desired function. I've had to work with well written code that was written in this style and it becomes very difficult to understand the code. (ArrowAntiPattern
) When needed (which is not that often), exceptions provide an excellent alternative way of returning errors and they do not lead to clutter throughout the code. --WayneMack
It seems to me that the only options offered are to raise an exception in response to an error, or to return a error code of type Boolean or Integer. Why not represent the concept of a function result as an object? One could define a class 'FunctionResult?
' with a property ReturnValue?
as Variant (speaking REALbasic here) and add any other error-handling capability one wants to this class. --CharlesYeomans
Inline error handling is more verbose but easier to understand: everything related to the behavior of the algorithm is on the same page and you can trace all paths in your head. A competent programmer can write solid, maintainable and secure code, while a lazy programmer will ignore error handling and create an unstable mess that works perfectly on his machine and only misbehaves when deployed.
Exceptions are nice in that they force the programmer to handle errors. The bugy program cannot behave incorrectly but cannot run either, see most GUI Apps written in Python, the standard library of which makes liberal use of unchecked and undocumented exceptions. The immediate reaction of the lazy programer is the paranoid handler: everything is wrapped so now you have a bugy program that can no longer be understood and fixed.
The correct approach IMHO is to use exceptions just for exceptional cases (SQL syntax, out of memory etc.) that the caller is certainly unable to resolve and that make the whole algorithm meaningless and that can only be handled in a higher level. On the other hand, for regular errors that the caller should expect and be able to recover from (not yet ready, DNS failure etc.) you should not raise an exception but return an error code and document it. It's nice to combine the two approaches so that an unhandled error turns into an exception: for example allocate and return the pointer to a result structure that is NULL in the case of an error, forcing the caller to crash.
We could certainly use better syntax that forces errors to be acknowledged without breaking code locality and exploding cyclomatic complexity.