The Right Approach to Exceptions

Jonathan M Davis jmdavisProg at gmx.com
Sun Feb 19 23:38:45 PST 2012


On Monday, February 20, 2012 01:10:39 Andrei Alexandrescu wrote:
> On 2/20/12 12:44 AM, foobar wrote:
> > I just died a little reading this. Are you suggesting that in order
> > to handle IO exceptions I need to: try { ...whatever... } catch
> > (PackageException!"std.io") {...} } catch
> > (PackageException!"tango.io") {...} } catch
> > (PackageException!"otherLib.io") {...} ...
> > 
> > What the hell is wrong with just using an IOException?
> 
> There's nothing wrong, but there's a possible misunderstanding. If
> tango.io and otherLib.io cooperate with std, then they'd originate
> exceptions in std.io (as opposed to their own). Do note that the issue
> is exactly the same if libraries use IOException - they all must agree
> on using the same nomenclature, whether it's called
> PackageException!"std.io" or IOException.
> 
> ModuleException and PackageException have one important thing going for
> them: they automate away a good amount of boilerplate, which makes them
> interesting for me to look at, and worth sharing as long as we're
> brainstorming. The associated issues as clear as the advantages.
> Probably ModuleException is too specific to be interesting, but
> PackageException seems useful.

It saves no boilerplate at the catch point, because you have to know what 
you're catching to do anything useful with it. It could be that you choose to 
catch a common exception rather than a specific one (e.g. IOException instead 
of FileException), but regardless of whether you use templates or mixins or 
whatever to generate the exception type's source code, you still need to write 
the handling code by hand. Handling code is _not_ the sort of thing that can 
be automated.

And as for saving boilerplate in defining exceptions, well some of that could 
be done via mixins, but since useful exceptions often have additional member 
variables, you're going to have to write many of them by hand anyway. _Some_ 
exceptions _could_ be done via mixins and the like when it's their type that 
matters and that's it, but I question that that's enough boilerplate to be a 
big deal - especially since it's not likely we should be adding exception 
types all the time.

I think that you're overestimating the amount of boilerplate code involved, 
and there are easy ways to reduce it without making exceptions be tied to 
modules or packages.

And as has been said before, ultimately the module that an exception comes 
from doesn't mean much. It's what went wrong that matters. And ideally, the 
standard library would have exception types that user code would throw or 
derive its own exception types from, in which case the exception types get 
even more divorced from the modules that they're declared in. So, ultimately, 
tying exceptions to modules or packages is _not_ a good idea in the general 
case. Sometimes it makes sense - particularly if you're talking about making a 
base exception type which a project as a whole uses (e.g. a PostgresException 
for a postgres library) - but in general, it's a bad approach, and it's one 
that we should be moving away from.

I say that we organize Phobos' exceptions into a proper hierarchy and then let 
other D projects derive from them or not as they see appropriate. But a 
standard set of exceptions should help standardize exceptions in D in general, 
even if not all libraries and projects choose to derive their exception types 
from the standard library's exception types.

We don't need to do anything elaborate with how exceptions are defined. We just 
need to organize them into a hierarchy. And it's not like we even have all 
that many exceptions to organize at the moment.

This thread was started due to a legitimate problem - the fact that our 
exception types are not always well chosen and definitely aren't always well 
organized. But that doesn't mean that we need to do anything new or fancy to 
fix the problem either.

- Jonathan M Davis


More information about the Digitalmars-d mailing list