The Right Approach to Exceptions

Juan Manuel Cabo juanmanuel.cabo at gmail.com
Mon Feb 20 17:02:41 PST 2012


oops, sorry!! I just saw a post by someone named Jose. My thousand apollogies!!

On 02/20/2012 10:01 PM, Juan Manuel Cabo wrote:
>>
>> Jose's argument convinced me otherwise. I retract my agreement.
>>
> ...
>>
>> No, I'm afraid there's a sizeable misunderstanding here.
>>
>>
>> Andrei
> 
> Hahah, yeah, I think there is a sizeable misunderstanding: unless you
> are referring to another guy with a spanish name in this thread,
> (which I haven't found). My name is Juan Manuel (people call me:
> Juanma, JM or Juan, but José is a first! I wouldn't mind John
> which is the 'translation' of my name).
> 
> Back to the nasty argument. I think that the example that everyone
> wants is this one. If anyone solves this one without Variant[string]
> then it's a better solution than Variant[string]. (I repaste it
> from an above reply I gave):
> 
>   [..]
>   For instance: a C library wrapper, which gets the library errors encoded
>   as some error code and throws them as exceptions. Shouldn't the library
>   throw a FileNotFoundException when that's the error, instead of throwing
>   a LibraryException that has the error code in a field?
> 
>   So the correct thing to do is: after a library call, the wrapper
>   checks the last error code number with a switch statement, and deciding
>   which standard exception type to throw (defaulting to whatever you like
>   if the error code doesn't map to a standard D exception). Then you
>   add the error code to the Variant[string], and any other extra info.
> 
>   That way, exception types can be standard.
> 
>   So, to keep D exception types standard reusable and respected by
>   future code, you must follow the Open-Closed design principle
>   (nicest principle of OO design ever).
>   [..]
> 
> Adding the Variant[string] is considered applying the great
> Open-Closed Design Principle:
> 	-Open for reuse.
> 	-Closed for modification.
>         http://www.objectmentor.com/resources/articles/ocp.pdf
> 
> --jm
> 
> 
> On 02/20/2012 09:38 PM, Andrei Alexandrescu wrote:
>> 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