The Right Approach to Exceptions
Jonathan M Davis
jmdavisProg at gmx.com
Mon Feb 20 10:23:04 PST 2012
On Monday, February 20, 2012 11:57:07 Andrei Alexandrescu wrote:
> On 2/20/12 11:44 AM, foobar wrote:
> > This extra processing is orthogonal to the exception. the same exception
> > can be logged to a file, processed (per above example) and generate
> > graphical notification to the user, etc. The exception contains the
> > information pertaining only to what went wrong. the rest is not part of
> > this discussion.
> Exactly. I don't see how a disagreement follows from here. So isn't it
> reasonable to design the exception such that it can offer information
> pertaining to what went wrong, in a uniform manner?
In most cases, that's not even vaguely possible. An exception for a socket
would probably include an IP and port in its additonal information. An
exception for a file operation would include the file name that it tried to
operate on. An exception for malformed unicode would include information on
the string and the bad character. An exception from parsing XML would give you
information about which part of the XML had the problem and what the problem
was. All of these situations are completely different. Using a Variant is the
equivalent of using a void* and casting to the actual information based no the
type of the exception or on a type code in the exception. How is that better
than simply having an actual exception hierarchy with each of the derived
exceptions having fields specific to their circumstances? I contend that it's
far worse. It's throwing away type information simply in an effort to
genericize. Genericity can be very useful, but it can also be over-applied.
I don't see how you could possibly make that uniform. It's very non-uniform by
its very nature. The handling _needs_ to be non-uniform.
> > The exact same exception in the example would also be thrown on a
> > mistyped URL in an application that tries to scrape some info from a
> > website for further processing. The error is still the same - the url is
> > incorrect but different use cases handle it differently. In the former
> > example I might call to a i18n lib (someone already mentioned gettext)
> > while in the latter I'll call a logging library with the the mistyped
> > url (for statistics' sake).
> > in the first I use the url to find a closest match, in the second I want
> > to log said requested url. Both handled by *other* mechanisms.
> > in both cases the exception needs a url field and in both cases I have
> > no need for the Variant[string] map.
> The Variant[string] map saves a lot of duplication whenever you want to
> format a human-readable string (which is a common activity with
> exceptions). It transforms this (I'm too lazy to write code anew by
> hand, so I'll paste Jonathan's):
> The stringTemplate function loads the formatting template from a table
> indexed on typeid(e).toString() and formats it with the info. It's
> simple factorization.
That only works in this particular case, because it happens that the code is
just figuring out how to translate the exception into an error message without
trying to recover. If you want to do anything fancier (like suggest the flag
that the user probably meant), you need those extra fields in the exceptions.
Also, much of the time, the application is going to want to print its own
error messages, not what library that its calling used. And frequently, the
application can give much better messages, because it knows what it's doing,
not just the operation that it tried and failed. Exceptions are for
_developers_, not users, and in general, exception messages should not be
printed to users.
And moving any messages that exceptions have out of the exception itself is
_bad_ for debugging. The exception should contain its own information, not
have it externalized for internationalization purposes. If its in the
exception itself, you can see it in the debugger. That doesn't work anywhere
near as well when you externalize its stuff.
I gave the getopt example, because we were talking about getopt, and it was
easy to write. It shows one way that the fields in the exception could be
useful. But it's an abnormality in that it's whole purpose is to allow you to
figure out how to best give an error message to the user. Many, many other
exceptions need to be processed by the program without necessarily informing
the user of anything. So, getopt was probably a bad example. It just was an
easy one to give.
- Jonathan M Davis
More information about the Digitalmars-d