The Right Approach to Exceptions
Juan Manuel Cabo
juanmanuel.cabo at gmail.com
Mon Feb 20 17:01:03 PST 2012
>
> 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