Boost logo

Boost :

From: Pavel Vozenilek (pavel_vozenilek_at_[hidden])
Date: 2006-08-08 20:16:28


"Emil Dotchevski" wrote:

>>>>> http://article.gmane.org/gmane.comp.lib.boost.devel/146322
>>>
>> } catch(boost::exception& e) {
>> e.dump_everything(); // what happened?
>> }
>
> Yes, but what does dump_everything() look like?
>
> The reason why this is important is that I can't imagine dump_everything
> being able to format a proper user message. The best it can do is dump
> stuff
> in a debug log, for example. Which begs the question, how do you format a
> proper message for the user? I think that the only way to do this is for
> the
> code that formats the message to *know*, for each class of exceptions,
> what
> info could be available. You can't parameterize this with a "visitor"
> interface. Or can you? That was my intention when I asked you for an
> example: what's in dump_everything?
>

Would it be possible to use typeid(..).name()
together with lexical_cast<> on the values?

The formatting is almost irrelevant at this
point, raw data are.
The end user woudn't see it, only the author.

>> typeswitch:
>> if (dynamic_cast<This>(e)) .... else
>> if (dynamic_cast<That>(e)) ....
>
> What's wrong with
>
> catch( This & )
> {
> }
> catch( That & )
> {
> }
>

This looses the valuable simplicity
of catch (boost::exception&).
And what if you want to add the same
10 data items for every exception.

[ snip visitor-like approach vs individual catch statements ]
>
> My personal opinion is that a list of ordered catch statements is the
> simplest way to get what you need. And it is directly supported by C++.
>

Problems:

* Coupling. The code containing catch is likely
   already complex and now it needs to include
   all handled exceptions, even if they are from
   lower layer.

   With the other approach you may create
   visitor in lower layer and provide it as part
   of its interface.
   The visitor would not need to know about higher
   layer but would work correctly, the upper layer
   would not depend on lower layer details
   (definitions of the exceptions).

* Isolation of error handling.
  With sequence of catch you put error handling
  code into vicinity of normal-path code.
  The code is spread across many functions.

   With visitor you can put error handling code
   into one central location and can completely
   isolate it from normal-path code.
   Only visitor definition needs to be shared.

* Not dynamic. Behaviour of a hardcoded catch sequence
  cannot be changed easily. A visitor fares better.
  Not really earth shaking feature but may come handy.

  Example: the visitor itself may be payload
  of the thrown exception. On each catch level
  it will be invoked and when it decided
  the error has been solved it will stop propagating
  the exception up.
  Say std::bad_alloc that "auto-stops"
  when enough of memory has been released.

  Better example: regression test suite.
  You created and use debug visitor that stops
  propagating of exceptions up and you may safely
  throw and test anything from lower layer w/o worry
  what disaster will it cause somewhere up.

* It is shorter:

   } catch (boost::exception& e) {
        my_visitor v;
        v.process(e);
   }

   vs.

   } catch (exception1& e) {
       handle(e);
   } catch (exception2& e) {
       handle(e);
   } catch (exception3& e) {
      handle(e);
   } ....

* Safety: the correct ordering of the
   checking is (should be) automated
   with a visitor. Finding bug in
   hand-written catch sequence
    is very hard.

* If you add new exception or change
   exception hierarchy you need to
   update only the visitor class, not every
   catch.

/Pavel


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk