The Right Approach to Exceptions

H. S. Teoh hsteoh at quickfur.ath.cx
Mon Feb 20 19:05:26 PST 2012


On Mon, Feb 20, 2012 at 08:32:08PM -0600, Andrei Alexandrescu wrote:
> On 2/20/12 7:08 PM, H. S. Teoh wrote:
> >On Mon, Feb 20, 2012 at 06:38:08PM -0600, Andrei Alexandrescu wrote:
> >[...]
> >>>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.
> >
> >Then it's useless for i18n, unless you can magically translate a
> >sequence of unknown values into a different language in a consistent
> >way.
> >
> >It sounds like all this is good for is to print a list of "name=value"
> >pairs. Which is useful, I'll admit, for development/debugging purposes.
> >I don't see how such a thing is useful in i18n.
> 
> As I said, string templates in conjunction with name/value bindings is
> all that's needed for i18n.

And how would such templates be designed, if what is available in the
bindings changes depending on the code path that led to the exception?

I agree with you that this allows the catch block to do stuff like pass
the entire hash to the i18n formatter without needing to know what's in
it. And conceivably, the formatter doesn't need to know either, it just
gives the bindings to the string templates. But the string templates
themselves have to know what's in the bindings. In fact, they *assume*
that certain bindings are in there. And when the expected bindings are
not there, then the template can't be applied. And you couldn't possibly
know this until runtime.

Whereas if the fields were fixed at compile-time, then the compiler
could verify that what the code thinks is there, is actually there.


[...]
> Exactly, and with this you just destroyed your own design. For it does
> not build any polymorphic interface, no abstraction. It forever forces
> code to toil in the concrete (_fileName, _ipAddress, _userName) and
> fails to elevate any common interface that would foster reusable code.

No. With RTTI, there's no need to toil in the concrete at all. Loop over
whatever fields happen to be in the object, hand them off to the
formatter or whatever it is wants to use them, job finished.

The only time you explicitly refer to _fileName, _ipAddress, etc., is
when you *specifically want to deal with them*. This is where you *want*
the compiler to statically verify that _fileName actually exists in that
object. Rather than wait till runtime and then the catch block realizes
oops, the field doesn't exist.

I'm not negating the fact that the hash is useful for *some* things. I'm
just saying that there are occasions where it *shouldn't* be used. There
are times when you need compile-type type-checking.


[...]
> On the contrary. This builds abstraction:
> 
> class Exception
> {
>     bool transient();
>     Variant[string] info();
>     ...
> }
> 
> because it allows client code to treat different types, even types
> that haven't even been defined yet, uniformly.

I see your point. But doesn't RTTI already fill the need of genericity?
Why not take advantage of compiler-time type checking where it's
possible?

You can still have the hash for runtime-added stuff, like adding
properties to exceptions in transit. I can see a use for that. But why
must *everything* be stuffed into the hash?


[...]
> >Then pray tell how "simple iteration" will achieve the translation of
> >the data in Variant[string] into a localized string, when there is no
> >guarantee any field will be in the hash at all. Format strings
> >obviously won't work, since you can't have a format string unless you
> >already know what arguments are present.
> 
> There's no guarantee. That'll be a runtime check in the formatting
> engine.
[...]

So in order for the format string to *not* fail at runtime, the
exception must always have the same fields in the bindings, right? Isn't
that the same thing as defining the fields statically and using RTTI
to iterate over them? That way, the compiler can verify at compile time
that the fields are actually there.


T

-- 
Real Programmers use "cat > a.out".


More information about the Digitalmars-d mailing list