The Right Approach to Exceptions

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Mon Feb 20 07:49:50 PST 2012


On 2/20/12 1:38 AM, Jonathan M Davis wrote:
> On Monday, February 20, 2012 01:10:39 Andrei Alexandrescu wrote:
>> 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.

Absolutely. For catching we're looking for allowing centralization, not 
for automation.

> 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.

Again, I think this thread clarified we need the "Variant[string] info;" 
member however we define the hierarchy.

Also, I think we can do better than defining the boilerplate constructor 
(see e.g. https://github.com/D-Programming-Language/phobos/pull/439). 
It's just a function. Consider:

// this goes in the stdlib
void raise(ConcreteException)(string message, Throwable t = null, string 
f = __FILE__, size_t l = __LINE__)
{
   auto r = new ConcreteException;
   r.message = message;
   r.file = f;
   r.line = l;
   r.next = t;
   throw r;
}

class AcmeException : Exception {}

Now whenever you want to raise AcmeException, you say 
raise!AcmeException("message"). Also, raise may accept additional data 
that fills the Variant[string]. That makes exception definitions one-liners.

> 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 tend to agree, particularly because it's easier for people to remember 
express names instead of origins encoded by module. Ironically, many of 
Phobos' exceptions today follow the exception-to-module correspondence. 
Still I think it's worth keeping in mind the possibility of having the 
PackageException as a base trail for various exceptions specific to a 
package.


Andrei


More information about the Digitalmars-d mailing list