The Right Approach to Exceptions

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Mon Feb 20 16:38:08 PST 2012


On 2/20/12 6:25 PM, H. S. Teoh wrote:
> On Mon, Feb 20, 2012 at 05:15:17PM -0600, Andrei Alexandrescu wrote:
> Formatting should use class reflection. We already discussed that, and
> we already agreed that was the superior approach.

Jose's argument convinced me otherwise. I retract my agreement.

> When you're catching a specific exception, you're catching it with the
> view that it will contain precisely information X, Y, Z that you need to
> recover from the problem. If you don't need to catch something, then
> don't put the catch block there.

That's extremely rare in my experience, and only present in toy examples 
that contain a ton of "..." magic.

> The problem with using Variant[string] is that everything gets lumped
> into one Exception object, and there's no way to only catch the
> Exception that happens to have variables "p", "q", and "r" set in the
> Variant[string].

No. You are still free to define as many exception classes as you deem 
necessary. Please let's not pit the hash against the hierarchy again. 
This is confusing the role of the two. Consider the hash an interface 
function you want to occasionally implement.

> You have to catch an exception type that includes all
> sorts of combinations of data in Variant[string], then manually do tests
> to single out the exception you want, and rethrow the rest. That's where
> the ugliness comes from.

Yah, that would suck, but it's not at all what I say.

> [...]
>> The code with Variant[string] does not need combinatorial testing if
>> it wants to do a uniform action (such as formatting). It handles
>> formatting uniformly, and if it wants to look for one particular field
>> it inserts a test.
>
> Again, we've already agreed class reflection is the proper solution to
> this one.

Agreement rescinded. Sorry! Jose's point was just too good, and reminded 
me of a pain point I so long had with exception, I'd got used to it as a 
fact of life.

>>> And then what do you do if you're depending on a particular field to
>>> be set, but it's not? Rethrow the exception? Then you have the stack
>>> trace reset problem.
>>
>> Don't forget that Variant[string] does not preclude distinct
>> exception types. It's not one or the other.
> [...]
>
> Agreed. But it shouldn't be the be-all and end-all of data passed in
> exceptions. If anything, it should only be rarely used, with most
> exception classes using static fields to convey relevant information.

And to perfectly help code duplication everywhere.

> I can see the usefulness of using Variant[string] as a way of
> "decorating" exceptions with "extra attributes", but it shouldn't be the
> primary way of conveying information from the throw site to the catch
> site.
>
> As for iterating over the information in the most derived class, for
> formatting, etc., class reflection is the way to go.

Agreement rescinded as far as exceptions go. That doesn't make 
reflection any less necessary btw. It just reflects the dynamism of 
exception paths.

> We shouldn't be
> using Variant[string] for this, because there's another problem
> associated with it: suppose MyException sometimes gets "extra_info1" and
> "extra_info2" tacked onto it, on its way up the call stack, and
> sometimes not. Now what should the catcher do?

Use a central loop to render the information.

> How do you format this
> exception?

With a string template as has been discussed.

> Should the format string include extra_info1 and extra_info2,
> or not? If it doesn't, what's the use of this extra info? If it does,
> what happens if these fields are missing?

Decision belongs to the string template engine.

> This is what I mean by not being able to depend on whether some data is
> there. Ultimately, to do anything useful with the info in the object,
> you need to know what's there.

No. You do realize you are positioning yourself straight against every 
OO principle there is? The entire OO world is predicated on the 
assumption you _can_ do useful stuff with an object WITHOUT knowing 
what's there.

> Preferably, the object's type will tell
> you exactly what's there, then you do a simple map from type to list of
> available attributes (e.g., map exception type to format string with
> known, static list of attributes). But if the type doesn't guarantee
> what data will be present, then your code becomes vastly more complex,
> you have to deal with potentially all possible combinations of what's
> there and what isn't.

I think you are misunderstanding the mechanisms involved. There is no 
combinatorial code, just simple iteration and such. Dealing with 
distinct exceptions with distinct code IS combinatorial, repetitive, and 
non-scalable.

> Instead of a single format string for a single
> exception type, you now have a combinatorial explosion of format strings
> for every possible combination of missing/present fields in the
> exception object.

No, I'm afraid there's a sizeable misunderstanding here.


Andrei


More information about the Digitalmars-d mailing list