« Ross Judson: AOP + Rules | Main | OOPs »

Dave Ely and Bob McWhirter on Exceptions

Ztuff

Dave Ely and Bob McWhirter responded to my little rant on exceptions. They really don't like the idea of String based exceptions, and are worth quoting at length:

Bob McWhirter:

I truly think that the idiom of using String messages as parameters for an exception and the getMessage() method have contributed to the uselessness of many exceptions. You're right that we all tend to getMessage() or printStackTrace(). I wouldn't say our exceptions are poor, but that our exception handling is. I try very hard to have meaningful constructors with meaningful parameters, and no messages, in my Exception hierarchy. public class NoSuchThingException extends Exception { public NoSuchThingException(ThingRepo repo, String thingId) { ... } public ThingRepo getThingRepo() { ... } pulibc getThingId() { .... } } The getMessage() is implemented in the class, and constructs a message using the accessors to the parameters of the constructor. So, my exception attempts to provide enough -context- to gracefully handle the exception. When all you get from your Exception is a String message, you have few options. With member data, your handling capabilities expand, and the usefulness of exceptions as a whole increases. If you really think exceptions are pointless, always throw a RuntimeException. You can still catch them when you need to, but otherwise, you can completely ignore them and have the JVM bomb out with the stacktrace you want.

Dave Ely:

Although I understand where this feeling comes from, I disagree with the whole darned concept. Exceptions are one of the more powerful and well done refinements that C++ introduced to C. They allow us to enforce the idiom of one entry point, one return point unless things go badly wrong. When done well, they also allow method level determinism of what can and can not be dealt with, and for more advanced applications, turning a problem into a solution. [...] This is same darned problem people still have in the C++ world, and most of them have never figured it out. String based exceptions are completely useless unless you employ parsers at every level of the application (and they make internationalization nearly impossible). Java has further contributed to the problem by making exceptions have some sort of context (a stack trace for example) but has not allowed developers to easily construct one exception type from another and retain that context. Inexperienced (and seasoned) developers alike are liable to create new exception types at the drop of hat for reasons I've never been able to fathom.

No argument there. I'm playing Devil's advocate by claiming exceptions are pointless when really the problem is that they're being abused by developers, particularly checked exceptions in Java.

The main objection to exceptions is that they make code complicated for questionable benefit. There are all these specialised exceptions, which aren't needed, and which result in the developers working against or around the system, because their job is that bit harder with the exception handling as designed. The whole point of exceptions was that it would simplify error handling - I'm not sure that's how things have worked out. Here is what (as likely as not) will happen to specialised, domain-oriented exceptions from worst to best case:


  • They'll get swallowed.
  • They'll get wrapped in an equally specious exception at a package boundary, and rethrown.
  • They'll get wrapped in a more general exception, and rethrown.
  • The code will reroute its excecution path in graceful fashion.

If you do get a wrapped exception, maybe the wrapper exception won't actually carry the cause exception's information through (personally I've seen my fair share of truncated InvocationTargetExceptions and ServletExceptions). Otherwise, I hope you've got the source to the dependency that failed - 'cos if you don't you working blind.

Exceptions need to be as general as possible to make them useful and used. This works just like security. The more hoops people have to jump through to obtain a secure system, the less secure the system becomes, because people will do dodgy (and maybe stupid) things to attain the levels of comfort they were at before the policy came along buggered everything for them. To someone, those hoops are crucial - to everyone else they're a pita. And paraphrasing William Gibson, You are One and They are Many. Dissonance happens and people will tend work around restrictive policies.

Worst of all, much of the time the specialised exceptions aren't needed; they're a twist on premature optimization, something that seemed like a good idea at the time. Designing them into mainline code is asking for trouble. The reason they're not needed is because exceptional behaviour doesn't have a whole lot to do with your domain, other than having happened there. The relationship between something like a boundary or resource exception and domain objects is tenuous at best, certainly not enough to require TheDomainBoundaryException. The stack trace should provide as much context about the domain than any kind of OO Hungarian error notation will.

Dave and Bob nonetheless have a valid point , getting applications to respond well to exceptions begs the code to respond to the exception's type, and not some number scraped out of getMessage(). To effect this, a protocol for failure needs to be designed. However, very little Java code works that way (though it sounds like Dave Ely is doing something very close).

It may well be that handling a class of exception behaviour in one place is a good thing and that an AOP approach could help normalize the code. I wonder then, is anyone using dynamic proxies or compiled aspects against exceptions as well as mainline code?

But most of time, an exception is thrown and it'll keep being thrown, up the stack until it reaches the attention of a human. The odd time it'll reach some code that can actually do something useful with it, other than log it and keep chugging. If what we do with 90% of exceptions is a glorified log line, then the design principles applied to logging can be applied to exceptions the primary one being get the line noise out of the way of the programmer's main line. But if you are actually doing something behaviorally interesting with exceptions, different rules apply, and my hat is off to you.

By the way, there are over 250 exception types in 1.4 JDK. I wonder, do we even need half of them? A quarter? An eighth? It's worth remembering, that as introduced by Java, checked exceptions are something of an experiment for mainstream programming. Python doesn't use them and C# dropped them. Bruce Eckel has this to say:

Checked exceptions seem like a really good idea at first. But it's all based on our unchallenged assumption that static type checking detects your problems and is always best. Java is the first language (that I know of) that uses checked exceptions and is thus the first experiment. However, the kind of code you must write around these things and the common phenomenon of "swallowed" exceptions begins to suggest there's a problem.

Disclosure: on JSR-87 (Java Agent Services), we're in public review and simply have too many exceptions in the API (more than 10). In fairness there's a lot that can go wrong, but we do have to factor some of those types out to make the API more usable. So I'm a guilty party, but learning.

CategoryException
Bruce Eckel
Robert Di Falco


February 2, 2003 05:06 PM

Comments

Jeffrey Winter
(February 5, 2003 02:27 AM #)

Well, for Servlet-based, REST-style applications I've found it very useful to adopt the AOP-esque abilities of Filters to capture Exceptions and report the details in the response.

Typically I extend ServletException into a ResourceException class that takes an HttpServletResponse status code in it's constructor. This is further extended as needed, such as for a MethodNotAllowedException that also requires the set of HTTP methods that *are* allowed, to be reported back in the response.

While this might not be quite as clean as a true AOP language that could allow most if not all of the "throws" clauses to be removed, I've found that I have been able to remove quite a bit of error handling code.

My approach to Exception handling has always been to package up as many details as will be useful to logging and the end user; but also to hide the underlying implementation details at the component boundries.

Steve Freeman
(February 8, 2003 01:26 AM #)

Checked exceptions came from (sadly missed) Modula-3. As always, Java took a good idea and didn't quite implement it properly. M3 had a pragma that could declare an exception as fatal within a scope, which meant that the program would just stop. That little trick makes them much easier to work with. The other point is that the exception hierarchy needs as much attention as the class hierachy, but many people don't have the habit.

If you're using static typing (a contentious issue, I know), then it seems to me that you need to know all the possible routes out of a method.

Steve

Trackback Pings

TrackBack URL for this entry:
http://www.dehora.net/mt/mt-tb.cgi/909

Listed below are links to weblogs that reference Dave Ely and Bob McWhirter on Exceptions:

» cow.mpeg from James Strachan's Radio Weblog
cow.mpeg . [Read More]

Tracked on December 4, 2003 08:31 PM