Boost logo

Boost :

From: Tobias Schwinger (tschwinger_at_[hidden])
Date: 2007-10-03 06:27:58


Emil Dotchevski wrote:
>> Oh my, I missed it. I should've read this part of the reference docs
>> inspecting the library as that multiple inheritance approach seems
>> highly questionable to me for the following reasons:
>>
>> 1. We can't access the data in the "traditional exception" the
>> Boost.Exception way (it's not tagged), and
>
> This is exactly the same behavior as if you write an exception class
> that derives from boost::exception and adds its own functionality,
> which I wouldn't consider to be a problem.
>
>> 2. calling 'what' is probably ambiguous and it seems generally awkward
>> to deal with that exception where (finally) caught.
>
> The exact type of the object returned by enable_error_info is
> unspecified; you're not supposed to catch the exception by that type.
>
> Of course you can catch it as a boost::exception, in which case what()
> is not ambiguous.

Of course! Stupid me...

> You can also catch it as its original type, in which case what() is
> also not ambiguous.

It doesn't make the design any better, however, as our exception still
has two independent interfaces. We can either catch one or the other -
user data is not integrated into the boost::exception.

>
> What do you mean by awkward?

Dealing with such a dual interface. Like having to cast between the two
to take advantage of the full functionality.

>>> Integration in Boost is even easier, as it can be done in a single
>>> place, in the boost::throw_exception function.
>> While technically possible, this measure requires the authors of
>> throwing libraries to reach consensus that it should happen - and a
>> single developer with objections might blow that plan.
>
> It is my understanding that calling boost::throw_exception when
> throwing an exception is a requirement, not a guideline.
>
> The price of the proposed use of enable_error_info in
> boost::throw_exception is one empty shared_ptr. In terms of space,
> this amounts to the size of two pointers added to all exception
> objects. Do you think that this would be a problem?

No. But design flaws sure wil1.

For the reasons pointed out above, I don't believe it's sound to throw
an empty boost::exception in this case.

>>>> Same goes for avoiding
>>>> boilerplate code and overhead compared to the traditional approach.
>>> Could you please explain? How does using Boost Exception require more
>>> boilerplate code than the traditional approach?
>> I mean the throw site:
>>
>> throw an_error(a,b,c)
>>
>> vs.
>>
>> throw an_error() << boost::error_info<a_tag>(a)
>> << boost::error_info<b_tag>(b) << boost::error_info<c_tag>(c)
>
> When you use boost::exception as a base class for an_error, nothing
> stops you from writing a constructor which takes a,b and c. Then you
> can throw an_error(a,b,c) as you would if you didn't use
> boost::exception. Compared to the traditional approach, I see no
> difference.

This approach provides better integration. But we're back in boilerplate
land (as you showed earlier in this thread).

Further, it adds so many unnecessary allocator invocations (unnecessary
as the library could provide means to avoid them together with the
boilerplate code as mentioned earlier) that will be over the top for
certain execution environments.

> I think that we disagree about this issue because without
> boost::exception, each and every throw needs to provide all info
> stored in the exception object, which is why it makes sense to write a
> constructor so that each throw is streamlined.
>
> With boost::exception, fewer throws pack the same data anyway. But of
> course you can write a constructor (as usual) if that's not the case
> (personally, I prefer using a namespace-scope function to do the same
> job, as I illustrated in another reply.)

Well, there is a lot of existing code that is written the "traditional"
way.

As mentioned several times, being able to add stuff in outer scopes is
most useful. That said, I think it's a mistake to promote it as the only
valid use case.

>> Currently it adds both boilerplate code and overhead when porting
>> existing code (in a way so that it throws first-class Boost.Exceptions,
>> that is).

^^ Bad phrasing, it seems.

>
> The easiest way to port existing code to using boost::exception is to
> use enable_error_info. This adds no boilerplate code, and requires no
> changes to any exception classes.

It doesn't make the data in the user exception first-class content of
the boost::exception.

 From my own experience I often found myself defending the review
version, coming to realize the vslue of one or the other suggestion
afterwards (and implementing it). So I'll just shut up and listen to
what else reviewers have to say :-).

Regards,
Tobias Schwinger
- Review Manager -


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