Re: [boost] Boost and exceptions

Robert Ramey wrote:
Dave Abrahams wrote:
I mean, if there is a problem with boost::throw_exception or any other part of Boost Exception, I'd like to know about it.
It seems clear to me from his posts that Robert wants to talk about the process and has forgotten any specifics about actual problems.
The problem was the gratuitious inclusion of a new dependency.
Emil has described repeatedly why the change was not gratuitous. That you fail to recognize the value in the change does not make it gratuitous. I looked at a recent boost/throw_exception.hpp. It includes boost/exception/detail/attribute_noreturn.hpp. That creates a dependency inversion that is unfortunate. That is, a top-level header file depends upon a header file of a library's files. That header is very short and has nothing Boost.Exception specific, so the code could be moved into boost/throw_exception.hpp or boost/detail/attribute_noreturn.hpp, for example. The header also conditionally includes the non-trivial boost/exception/exception.hpp, another dependency inversion, which defines many types and functions, and includes some inline function definitions: boost::exception_detail::refcount_ptr boost:: error_info boost::exception boost::exception_detail::error_info_base boost::exception_detail::type_info_ boost::exception_detail::error_info_container boost::exception_detail::get_info boost::exception_detail::get_diagnostic_information() boost::exception_detail::copy_boost_exception() boost::exception_detail::set_info() boost::exception_detail::error_info_injector boost::enable_error_info() boost::exception_detail::clone_base boost::exception_detail::clone_impl boost::enable_current_exception() If BOOST_EXCEPTION_DISABLE is not defined, then boost::throw_exception() tacks on Boost.Exception features to the exception being thrown. This is a non-trivial set of changes to make to the top-level header. I didn't follow the discussion at the time, but I'll presume there was a lot of discussion about the type and extent of these changes and that it was considered a good idea. In hindsight, I agree with Robert's assertion that there should have been a replacement function, boost::exception::throw_exception() or similar, to introduce the new functionality. Whether the existing function needed to be deprecated is a separate issue. The result is that libraries could knowingly choose the new version, and a dependency on Boost.Exception, or, if warranted, stick with the old. As things now stand, if there is good reason to avoid the new version, it can only be done by defining BOOST_EXCEPTION_DISABLE, which affects an entire build.
The extent/nature of any problem it created or didn't create is not relevant here. Just the injection of a new body of code which replaced two lines and added no functionality used/needed by the serialization library makes the any library which used boost::throw_exception "bigger" for no reason.
The issue you're raising, as I understand it, is dependency inversion: the top-level header brings a dependency on Boost.Exception.
It makes the library more "fragil". It means I have I a new place to look if something needs looking into. etc.etc.
As Nevin pointed out, your code will always be subject to the changes in those libraries on which it depends. The more dependencies you introduce, the more fragile your code becomes, but there's a great deal of benefit to reuse, too. The only issue in this case is that one can reasonably expect a top-level header to avoid dependencies on libraries.
So we'll just move on as Vicente suggested. That will be satisfactory from my standpoint.
That is the only way forward, if there is good reason to avoid the now longstanding changes to boost::throw_exception(). However, you should work with Emil to be sure you correctly and fully understand the issues before deciding that you cannot accept boost::throw_exception() as is. (I don't pretend to know what your concerns are. I just don't want to see a new throw_exception() variant if there isn't a compelling reason, and I don't consider your fragility argument compelling in this case.) _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com ________________________________ IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Stewart, Robert wrote:
Robert Ramey wrote:
Dave Abrahams wrote:
I mean, if there is a problem with boost::throw_exception or any other part of Boost Exception, I'd like to know about it.
It seems clear to me from his posts that Robert wants to talk about the process and has forgotten any specifics about actual problems.
The problem was the gratuitious inclusion of a new dependency.
Emil has described repeatedly why the change was not gratuitous. That you fail to recognize the value in the change does not make it gratuitous.
If you like you can substitute the term "unnecessary"
I looked at a recent boost/throw_exception.hpp. .... ... The issue you're raising, as I understand it, is dependency inversion: the top-level header brings a dependency on Boost.Exception.
That's it.
It makes the library more "fragil". It means I have I a new place to look if something needs looking into. etc.etc.
As Nevin pointed out, your code will always be subject to the changes in those libraries on which it depends.
LOL - that's precisely why I don't want to see unnecessary dependencies introduced. Especially when I'm not looking.
The more dependencies you introduce, the more fragile your code becomes, but there's a great deal of benefit to reuse, too. The only issue in this case is that one can reasonably expect a top-level header to avoid dependencies on libraries.
Personally I wouldn't say it's the only issue. But I'm glad we can agree that it's its a BIG issue.
So we'll just move on as Vicente suggested. That will be satisfactory from my standpoint.
That is the only way forward, if there is good reason to avoid the now longstanding changes to boost::throw_exception().
And how is that to be determined? Who would do that work?
However, you should work with Emil to be sure you correctly and fully understand the issues before deciding that you cannot accept boost::throw_exception() as is.
Ahhh - this is the rub.
(I don't pretend to know what your concerns are.)
LOL - you described them very well in your previous post. And you've supported your argument for my (general/abstract?) concerns with a meticulous analysis of the current implementation of boost::throw as particular example. Thank you for that.
I just don't want to see a new throw_exception() variant if there isn't a compelling reason, and I don't consider your fragility argument compelling in this case.)
You've looked into this - did you see any "compelling reason" to inject this code into the serialization or any other library? Robert Ramey

Robert Ramey wrote:
Stewart, Robert wrote:
Robert Ramey wrote:
Dave Abrahams wrote:
I looked at a recent boost/throw_exception.hpp. [snip] The issue you're raising, as I understand it, is dependency inversion: the top-level header brings a dependency on Boost.Exception.
That's it.
OK, good. I'm glad we've succinctly and clearly identified your concern. That means there's an opportunity to make progress and set policy.
It makes the library more "fragil". It means I have I a new place to look if something needs looking into. etc.
As Nevin pointed out, your code will always be subject to the changes in those libraries on which it depends.
LOL - that's precisely why I don't want to see unnecessary dependencies introduced. Especially when I'm not looking.
I get that. If the change was unnecessary, then it adds a dependency that complicates your maintenance. However, there's still the question of whether the dependency was necessary. You're convinced it wasn't, I know.
So we'll just move on as Vicente suggested. That will be satisfactory from my standpoint.
That is the only way forward, if there is good reason to avoid the now longstanding changes to boost::throw_exception().
And how is that to be determined? Who would do that work?
Clearly, those (you) with a concern would make a proposal, elicit discussion of the idea and proposed solution, then, if deemed acceptable, determine what sort of review process is warranted.
However, you should work with Emil to be sure you correctly and fully understand the issues before deciding that you cannot accept boost::throw_exception() as is.
Ahhh - this is the rub.
Yes, and it's a very important first step.
(I don't pretend to know what your concerns are.)
LOL - you described them very well in your previous post.
I'm not so sure. You've gone to some lengths to avoid the Boost.Exception dependency and, I presume, it was not motivated simply because you did not want Serialization being dependent upon Exception.
I just don't want to see a new throw_exception() variant if there isn't a compelling reason, and I don't consider your fragility argument compelling in this case.)
You've looked into this - did you see any "compelling reason" to inject this code into the serialization or any other library?
I don't know what benefits it may bring to Serialization and that's the crux of the matter. Roger Martin and Fabio Fracassi have both described the value they get from Boost.Exception and, presumably, from boost::throw_exception(), that they don't get from Serialization precisely because you have avoided the dependency. It is for reasons like those that I suggest reevaluating whether Serialization should accept boost::throw_exception() as is and avoid the fork. _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com ________________________________ IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On 22 June 2012 18:30, Robert Ramey <ramey@rrsd.com> wrote:
Stewart, Robert wrote:
The more dependencies you introduce, the more fragile your code becomes, but there's a great deal of benefit to reuse, too. The only issue in this case is that one can reasonably expect a top-level header to avoid dependencies on libraries.
Personally I wouldn't say it's the only issue. But I'm glad we can agree that it's its a BIG issue.
There are a lot of headers violating your rule. What problems has it caused?

The more dependencies you introduce, the more fragile your code becomes, but there's a great deal of benefit to reuse, too. The only issue in this case is that one can reasonably expect a top-level header to avoid dependencies on libraries.
Personally I wouldn't say it's the only issue. But I'm glad we can agree that it's its a BIG issue.
There are a lot of headers violating your rule. What problems has it caused?
I suspect that's true. Here's another point then - if the two small headers of Boost.Exception upon which throw_exception depends were moved into boost/detail/ - would that make you happier? I don't see it makes any difference myself: other perhaps than making a declaration that these are and will remain lightweight includes, and won't suddenly dump a whole bunch of other Boost.Exception code into your files. John.

on Fri Jun 22 2012, Daniel James <dnljms-AT-gmail.com> wrote:
On 22 June 2012 18:30, Robert Ramey <ramey@rrsd.com> wrote:
Stewart, Robert wrote:
The more dependencies you introduce, the more fragile your code becomes, but there's a great deal of benefit to reuse, too. The only issue in this case is that one can reasonably expect a top-level header to avoid dependencies on libraries.
Personally I wouldn't say it's the only issue. But I'm glad we can agree that it's its a BIG issue.
There are a lot of headers violating your rule.
Most notably, there are plenty of aggregate headers that do this.
What problems has it caused?
Good question. We do have two problematic dependency loops in Boost, but it's not caused by this sort of header structure: http://f.cl.ly/items/343N460u3b3039091C0g/deps.pdf -- Dave Abrahams BoostPro Computing http://www.boostpro.com

Dave Abrahams wrote:
on Fri Jun 22 2012, Daniel James <dnljms-AT-gmail.com> wrote:
There are a lot of headers violating your rule.
Most notably, there are plenty of aggregate headers that do this.
In a previous post, I specifically excluded "convenience headers" from being considered as "violating" this "rule". They are not at issue here. Robert Ramey

On 22 June 2012 15:40, Robert Ramey <ramey@rrsd.com> wrote:
In a previous post, I specifically excluded "convenience headers" from being considered as "violating" this "rule". They are not at issue here.
You keep asserting this, but I haven't seen you explain *what* makes the convenience headers so special that they do not violate your rule. -- Nevin ":-)" Liber <mailto:nevin@eviloverlord.com> (847) 691-1404

Nevin Liber wrote:
On 22 June 2012 15:40, Robert Ramey <ramey@rrsd.com> wrote:
In a previous post, I specifically excluded "convenience headers" from being considered as "violating" this "rule". They are not at issue here.
You keep asserting this, but I haven't seen you explain *what* makes the convenience headers so special that they do not violate your rule.
I'm sure of what "my rule" means. But I try to clarify my view.: I have no complaint or issue with headers whose function is to contain a list of library headers so that uses can include a bunch of related headers at with just one include statement. I have referred to this practice as a "convenience header" which I believe is common practice on this list. FWIW I presonally don't like "convenience headers" because I like to have a better idea of what I'm actually including. But let's chalk that up to personal taste and not anybody's problem. The following sort of example file:boost/throw_exception.hpp #include <boost/exception/.?.hpp> is what I'm objecting to. This means that when I my code contains #include <boost/throw_exception.hpp>
From reading the code, I don't it to expect to include a whole 'nother library. And that's they way it was before it was changed. The change created surprises for me - and I just like to minimize surprises. This is about writing code which does what it looks like it says it's going to do - no more no less.
Also note that I'm not saying that following the practice I recommend will solve all problems and avoid all surprises. But it contributes to diminishing them and also helps keep the program/library scope from expanding beyond the minimum it needs to be to do the job. It's not that complicated and I don't think it should be all that controversial. Robert Ramey

On 06/22/2012 08:33 PM, Dave Abrahams wrote:
Good question. We do have two problematic dependency loops in Boost, but it's not caused by this sort of header structure:
What are the loops here? What do the colored boxes and arrows mean? Also how were those dependencies defined? From analysis of header includes or just by hand? Also this doesn't seem to cover all of Boost.

on Sat Jun 23 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
On 06/22/2012 08:33 PM, Dave Abrahams wrote:
Good question. We do have two problematic dependency loops in Boost, but it's not caused by this sort of header structure:
What are the loops here? What do the colored boxes and arrows mean?
Each set of same-colored boxes is a SCC in the build dependency graph. Heavy black arrows are direct dependencies. Dashed arrows are dependencies introduced by usage-requirements (such as these: https://github.com/boost-lib/math/blob/master/CMakeLists.txt#L96). The blue ones are members of a transitive reduction of those usage dependencies. Ignoring the gray ones *might* make the structure easier to see.
Also how were those dependencies defined? From analysis of header includes or just by hand?
From automatically analyzing the CMakeLists.txt files in modularized Boost (https://github.com/ryppl/ryppl/blob/develop/scripts/dump_cmake.py). The entries in the CMakeLists.txt files were generated by automatically analyzing header files.
Also this doesn't seem to cover all of Boost.
You don't want to see that graph :-). It looks something like http://f.cl.ly/items/3V2I3A103K1Y45113s3w/source-deps.pdf The first one shows only the libraries with build dependencies, i.e. it eliminates all leaves in the build dependency tree. Since leaves can't participate in dependency cycles, that reduced view allows us to better understand the reasons for the SCCs. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On 23 June 2012 21:05, Dave Abrahams <dave@boostpro.com> wrote:
on Sat Jun 23 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
On 06/22/2012 08:33 PM, Dave Abrahams wrote:
Good question. We do have two problematic dependency loops in Boost, but it's not caused by this sort of header structure:
What are the loops here? What do the colored boxes and arrows mean?
Each set of same-colored boxes is a SCC in the build dependency graph. Heavy black arrows are direct dependencies. Dashed arrows are dependencies introduced by usage-requirements (such as these: https://github.com/boost-lib/math/blob/master/CMakeLists.txt#L96). The blue ones are members of a transitive reduction of those usage dependencies. Ignoring the gray ones *might* make the structure easier to see.
Is this something we should be doing something about? I guess the Boost.Math circle could possibly be broken by splitting Boost.Math into smaller modules (obviously up to John).
Also this doesn't seem to cover all of Boost.
You don't want to see that graph :-). It looks something like http://f.cl.ly/items/3V2I3A103K1Y45113s3w/source-deps.pdf
That's pretty crazy. Do you know if separating test dependencies would make much of a difference?

on Sat Jun 23 2012, Daniel James <dnljms-AT-gmail.com> wrote:
On 23 June 2012 21:05, Dave Abrahams <dave@boostpro.com> wrote:
on Sat Jun 23 2012, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
On 06/22/2012 08:33 PM, Dave Abrahams wrote:
Good question. We do have two problematic dependency loops in Boost, but it's not caused by this sort of header structure:
What are the loops here? What do the colored boxes and arrows mean?
Each set of same-colored boxes is a SCC in the build dependency graph. Heavy black arrows are direct dependencies. Dashed arrows are dependencies introduced by usage-requirements (such as these: https://github.com/boost-lib/math/blob/master/CMakeLists.txt#L96). The blue ones are members of a transitive reduction of those usage dependencies. Ignoring the gray ones *might* make the structure easier to see.
Is this something we should be doing something about?
Yes, eventually.
I guess the Boost.Math circle could possibly be broken by splitting Boost.Math into smaller modules (obviously up to John).
There are a few libraries that are substantially, but not completely, usable without their compiled component. That is to say, they're header-only except for a few features. If in each case, those few features were split into their own module, this issue would go away.
Also this doesn't seem to cover all of Boost.
You don't want to see that graph :-). It looks something like http://f.cl.ly/items/3V2I3A103K1Y45113s3w/source-deps.pdf
That's pretty crazy. Do you know if separating test dependencies would make much of a difference?
They're already separated, along with documentation dependencies. You *really* don't want to see the graph that includes the test dependencies ;-) Cheers, -- Dave Abrahams BoostPro Computing http://www.boostpro.com

Daniel James wrote:
On 22 June 2012 18:30, Robert Ramey <ramey@rrsd.com> wrote:
Stewart, Robert wrote:
The more dependencies you introduce, the more fragile your code becomes, but there's a great deal of benefit to reuse, too. The only issue in this case is that one can reasonably expect a top-level header to avoid dependencies on libraries.
Personally I wouldn't say it's the only issue. But I'm glad we can agree that it's its a BIG issue.
There are a lot of headers violating your rule.
assuming that's true, it's a bad idea there as well.
What problems has it caused?
lol - this discussion for one. But your comments are sincere and really deserve a more serious answer so I'll try to supply one. TL;DR Someone comes up with some idea for a program/application/library or whatever. This idea is meant to solve some problem that this person has in mind. At this point - any subsequent point, this idea will move in two directions a) It will become more specific and narrowed in scope and evolve into a very clear concept what can easily be grasped as to what it's function is. We have great examples of this in boost - shared_ptr static_assert. Deeper understanding How to recognize a) 1) You use it or incorporate into your app in a very short time because it's easy to understand what it does and how to use it. 2) you use it and you forget you used it because it caused no surprises. 3) It works for years without a hassle 4) it saves total work - rather than expanding it. 5) if anything breaks - its easy to find the cause and the person who should fix it. b) It can evolve into a more amorpheous and all encompassing idea that looks more like a "bag of features" rather than a coherent concept which one can understand immediately and systematically unwrap to understand at a more detailed level. We have some software in boost which exmplefies this. How to recognise b) 1) It might look simple to use, but turns out to consume a lot of time when you try to use it. (I love it when a salesman demonstrates how simple something is to use and I take it home - and damned if I'm not mystified by it!) 2) It's has surprising behavior 3) It breaks when you don't expect it 4) if you complain - it's "your fault" because you didn't understand how to use it, didn't read the docs, didn't look the code or whatever. 5) It adds total work rather than diminishing it. 6) it becomes hard to determine who is responsable for problems when they occur. Of course these are idealized descriptions no library/application will fall 100% in either camp. This description applies to a lot more stuff than just software - see the book "The design of everyday things". Even if the idea is seems clearly defined, as time goes on there is a huge amount of pressure to add "just one feature" because someone would find it useful. The result is that the original idea morphs from a clearly defined purpose to some sort of .... well hard to describe. The project start's to suffer from the symptoms in b) above. Projects in the "b)" category tend to grow and die of a combination of obesity, weakness, lack of direction. Basically they tend ot become victims of their own success. I realize this is "just one feature which a lot of people would find useful" but who speaks for the people who don't find it useful? I do. You're thinkng this is a one time special case. But it's not. I fight a constant running battle to keep the serialzation library from evolving into something that is unmaintainble, overly bloated, harder to understand and use, etc. I can't tell you how many times I've had to disappoint someone who feels they need this "one more tihng". So now maybe you can understand how I can object to having this "great feature" injected into the library without my knowing about it. I'm not intending to be the "savanorla" of boost, C++, or software developement practices. I just happened to be the person at the scene of this particular accident. Robert Ramey

On 22 June 2012 20:41, Robert Ramey <ramey@rrsd.com> wrote:
Daniel James wrote:
On 22 June 2012 18:30, Robert Ramey <ramey@rrsd.com> wrote:
Stewart, Robert wrote:
The more dependencies you introduce, the more fragile your code becomes, but there's a great deal of benefit to reuse, too. The only issue in this case is that one can reasonably expect a top-level header to avoid dependencies on libraries.
Personally I wouldn't say it's the only issue. But I'm glad we can agree that it's its a BIG issue.
There are a lot of headers violating your rule.
assuming that's true, it's a bad idea there as well.
From a quick look there's more than twenty, possibly a lot more. I'm not counting headers which just include other headers. There used to be more, I moved the implementation of the unordered containers into subdirectories to make version control easier. Peter Dimov moved all of his libraries' implementation into subdirectories as well, I'm not sure what his motivation was.
I suspect that this might be a different perception of what a top level header means. When I was first involved with boost (I think Emil got involved a little while later) this was pretty much standard practice. I guess that when you were first involved (a few years earlier) it might have been reserved for more self contained headers. After I'd been involved for a while, people started to get concerned as more and more libraries were added and wanted a bit more structure. Although from what I recall they were more concerned with the boost namespace getting crowded.
a) It will become more specific and narrowed in scope and evolve into a very clear concept what can easily be grasped as to what it's function is. We have great examples of this in boost - shared_ptr static_assert. Deeper understanding
Well, shared_ptr has evolved. The interface has remained mostly constant, but the internals have changed quite a lot, which has caused some issues, particularly on more obscure platforms. Also, some libraries, while well defined and self contained have gained dependencies. For example, here are Boost.Array's dependencies: DEPENDS BoostConfig BoostCore BoostException BoostFunctionalHash BoostUtility (for swap) In terms of headers, it's still light, and, ignoring exception for a moment, supporting our standard hash and swap functionality seems pretty essential to me (obviously, I am biased here). I've been getting a bit annoyed with how I'm accumulating dependencies in Boost.Unordered, but it's hard to avoid if I want to support C++11 features (e.g. to implement 'piecewise_construct' I had to add a dependency on Boost.Tuple).
So now maybe you can understand how I can object to having this "great feature" injected into the library without my knowing about it.
If it wasn't clear, I was asking specifically about including headers from sub-directories in a top level header.

Daniel James wrote:
Peter Dimov moved all of his libraries' implementation into subdirectories as well, I'm not sure what his motivation was.
I found this physical organization more convenient and better suited for the current release procedure. One can do a svn log on the library subdirectory, for example. It also happens to help the effort to make Boost modular. :-)

Daniel James wrote:
On 22 June 2012 20:41, Robert Ramey <ramey@rrsd.com> wrote:
Well, shared_ptr has evolved. The interface has remained mostly constant, but the internals have changed quite a lot, which has caused some issues, particularly on more obscure platforms.
lol - that's the way it's suppose to be. Time for a story. When I first made the serialization library, I couldn't serialize a shared_ptr. In order to do it I needed for shared_ptr to include friend::serialization. I asked Peter to do this and refused in a pretty abrupt way. This really annoyed me. After all, it was no big deal for him to add this one line!!!. His point was that by doing this it would tie his hands in the future implementation of shared_ptr. After some time I came to understand why he was right and I was wrong. As you can imagine this is sort of a rare event. I know it's not exactly the same as the current situation but it's similar in my view.
Also, some libraries, while well defined and self contained have gained dependencies. For example, here are Boost.Array's dependencies:
DEPENDS BoostConfig BoostCore BoostException BoostFunctionalHash BoostUtility (for swap)
In terms of headers, it's still light, and, ignoring exception for a moment, supporting our standard hash and swap functionality seems pretty essential to me (obviously, I am biased here).
I've been getting a bit annoyed with how I'm accumulating dependencies in Boost.Unordered, but it's hard to avoid if I want to support C++11 features (e.g. to implement 'piecewise_construct' I had to add a dependency on Boost.Tuple).
So now maybe you can understand how I can object to having this "great feature" injected into the library without my knowing about it.
If it wasn't clear, I was asking specifically about including headers from sub-directories in a top level header.
This is a little confusing. Here is the way I think about it. "standard library" - the C++ standard library. "core library" - things that directly are in namespace/directory boost and depend only on other "core libraries" or the C++ standard library example boost_static_assert, boost_non_copyable. "application library" - thingls that are in their own namespace/directory and can depend upon anything. example serialization, exception, etc. "user header" - a header expected to be used by library users as opposed to something internal to the library. "convenience header" - a file with a list of includes for all the user headers for a particular library. rules: "core library" code can only call other core library modules "application library" code can call anything directory names should match namespace names. misc: boost/utility - an application library which includes a bunch of small applications Much of Boost falls together along these lines anyway. There are some notable exceptions boost.range is in the boost namespace but in the directory, a bunch of others etc. This is very helpful to me when I write code (to the extent that its true). It gives me a very clear idea of what I'm sucking into the library/application. Sometimes I'll include a large header just for one tiny function and I can see that when I do it. I can decide on a case by case basis as to which library function I might replace with a home brew version. I think were sort of on the same page here. The only thing I would differ with what you've said is that I don't believe Boost exception adds anything when called from a library. To me it's a "user code" facility. Robert Ramey

On 24.06.2012, at 00:56, Robert Ramey wrote:
Daniel James wrote:
On 22 June 2012 20:41, Robert Ramey <ramey@rrsd.com> wrote:
Well, shared_ptr has evolved. The interface has remained mostly constant, but the internals have changed quite a lot, which has caused some issues, particularly on more obscure platforms.
lol - that's the way it's suppose to be.
Time for a story. When I first made the serialization library, I couldn't serialize a shared_ptr. In order to do it I needed for shared_ptr to include friend::serialization. I asked Peter to do this and refused in a pretty abrupt way. This really annoyed me. After all, it was no big deal for him to add this one line!!!. His point was that by doing this it would tie his hands in the future implementation of shared_ptr. After some time I came to understand why he was right and I was wrong. As you can imagine this is sort of a rare event. I know it's not exactly the same as the current situation but it's similar in my view.
I completely disagree. They're not at all similar. You asked him to expose the implementation details of shared_ptr to you, a consumer of his library. By doing this, his library internals would have become interface, blocking change. Every implementation change would have been an interface change. The change to throw_exception didn't do any such thing. It didn't change the interface. It didn't expose implementation details. All it did was change the implementation of an existing interface in a compatible (modulo bugs, and tightening the compile-time checking in a place where it was previously too lenient) way, and add a small dependency on a part of Boost.Exception along the way. Sebastian

I just don't want to see a new throw_exception() variant if there isn't a compelling reason, and I don't consider your fragility argument compelling in this case.)
You've looked into this - did you see any "compelling reason" to inject this code into the serialization or any other library?
Let's try and give some examples: 1) Unlike "regular" exception objects, objects which derive from boost::exception can have additional information added to them either at the call site, or later in the call stack. Consider this case: user opens a std::fstream and passes the object to a serialization method which then throws. Currently you may get some information about the failure, but not the file name because serialization doesn't know what that is (as far as I know). However, with Boost.Exception support, the calling code can annotate the already thrown exception, retaining all the information it contains, but adding whatever extra information (file name for example) is available. See http://www.boost.org/doc/libs/1_49_0/libs/exception/doc/tutorial_transportin.... 2) As others have already mentioned, Boost.Exception allows arbitrary exception objects to be cloned, amongst other things, this allows exceptions to propagate across threads. For example if a serialization routine is run as a future (quite a reasonable goal), then it would allow exceptions thrown during serialization in the worker thread, to be re-thrown in the calling thread when the result of the future is acquired. See http://www.boost.org/doc/libs/1_49_0/libs/exception/doc/tutorial_exception_p.... 3) Boost.Exception provides additional information about from where the exception was thrown (file and line number etc), this can be extremely useful in diagnostic situations when an exception was "unexpected". See http://www.boost.org/doc/libs/1_49_0/libs/exception/doc/tutorial_diagnostic_.... For me, I've only used (3), but when you need it it's very useful. Both (1) and (2) look like killer use cases to me - not for you - for your users. HTH, John.

John Maddock wrote:
I just don't want to see a new throw_exception() variant if there isn't a compelling reason, and I don't consider your fragility argument compelling in this case.)
You've looked into this - did you see any "compelling reason" to inject this code into the serialization or any other library?
Let's try and give some examples:
I really didn't want to get is these specifics. But you've sucked me in.
1) Unlike "regular" exception objects, objects which derive from boost::exception can have additional information added to them either at the call site, or later in the call stack. Consider this case: user opens a std::fstream and passes the object to a serialization method which then throws. Currently you may get some information about the failure, but not the file name because serialization doesn't know what that is (as far as I know). However, with Boost.Exception support, the calling code can annotate the already thrown exception, retaining all the information it contains, but adding whatever extra information (file name for example) is available. See http://www.boost.org/doc/libs/1_49_0/libs/exception/doc/tutorial_transportin....
Why does the serialization library have to include code from boost exception in order to do this? You can use boost exception at the same place, catch the standard exception that the serialization throws, construct you're own boost exception and continue on.
2) As others have already mentioned, Boost.Exception allows arbitrary exception objects to be cloned, amongst other things, this allows exceptions to propagate across threads. For example if a serialization routine is run as a future (quite a reasonable goal), then it would allow exceptions thrown during serialization in the worker thread, to be re-thrown in the calling thread when the result of the future is acquired. See http://www.boost.org/doc/libs/1_49_0/libs/exception/doc/tutorial_exception_p....
again the same question.
3) Boost.Exception provides additional information about from where the exception was thrown (file and line number etc), this can be extremely useful in diagnostic situations when an exception was "unexpected". See http://www.boost.org/doc/libs/1_49_0/libs/exception/doc/tutorial_diagnostic_....
For me, I've only used (3), but when you need it it's very useful. Both (1) and (2) look like killer use cases to me - not for you - for your users.
Let me be clear. I don't have any complaint about boost exception per se. My complaint is the process by which it was inject. BUT - now you've sucked me into looking at the merits of including it, I don't see that it would be of any use. here's typical serialization code: #include <boost/archiive/binary_iarchive.hpp> #include <ifstream> ... f(...){ ifsteam is("my file") binary_iarchive ia(is); try { my_data d; ia >> d; } catch(boost::archive::exception ae){ std::cout << ae.what(); throw(ae) ; // or throw something else } return; } So if I want to use boost exception I would just write #include <boost/archiive/binary_iarchive.hpp> #include <ifstream> #include <boost/exception/???.hpp> ... f(...){ ifsteam is("my file") binary_iarchive ia(is); try { my_data d; ia >> d; } catch(boost::archive::exception ae){ std::cout << ae.what(); // I don't know how to use boost::exception insert your own code here boost::exception::throw(?) } return; } I don't see injecting boost::exception into the serialization code changes this in any way Robert Ramey

On 06/22/2012 10:17 PM, Robert Ramey wrote:
Why does the serialization library have to include code from boost exception in order to do this?
You can use boost exception at the same place, catch the standard exception that the serialization throws, construct you're own boost exception and continue on.
So you're suggesting that people should reimplement the whole API of Boost.Serialization where each function call is wrapped in a try/catch with all the expected Boost.Serialization exception types? Sounds practical. How about Boost.Serialization directly uses a global togglable mechanism which can be set to use the feature or not instead?
I don't see that it would be of any use. here's typical serialization code:
Typical example code is irrelevant. In real life people build complex systems where several things can happen in different threads and you need to be able to transfer errors from one thread to the other. You also write generic code where you cannot predict in advance what the exact type of the exception you're gonna have is going to be.

On 6/22/12 10:17 PM, Robert Ramey wrote:
BUT - now you've sucked me into looking at the merits of including it, I don't see that it would be of any use. here's typical serialization code:
#include <boost/archiive/binary_iarchive.hpp> #include <ifstream> .... f(...){ ifsteam is("my file") binary_iarchive ia(is); try { my_data d; ia >> d; } catch(boost::archive::exception ae){ std::cout << ae.what(); throw(ae) ; // or throw something else } return; }
Well my typical code looks more like load(...) { ifstream is("myfile"); binary_iarchive ia(is); my_data d; ia >> d; return; } with the first try block "miles" away from the call. With a whole lot of layers in between. Layers which may or may not invoke threads. The use you don't see is that I can do this. By not using boost exception you force me to take extra care either everywhere I use serialization or everywhere I use threads. Its not much work, but it still inhibits a much cleaner abstraction level. regards Fabio

You've looked into this - did you see any "compelling reason" to inject this code into the serialization or any other library?
Let's try and give some examples:
I really didn't want to get is these specifics. But you've sucked me in.
Huh? I thought that's what you were asking for when you asked for "compelling reasons".
1) Unlike "regular" exception objects, objects which derive from boost::exception can have additional information added to them either at the call site, or later in the call stack. Consider this case: user opens a std::fstream and passes the object to a serialization method which then throws. Currently you may get some information about the failure, but not the file name because serialization doesn't know what that is (as far as I know). However, with Boost.Exception support, the calling code can annotate the already thrown exception, retaining all the information it contains, but adding whatever extra information (file name for example) is available. See http://www.boost.org/doc/libs/1_49_0/libs/exception/doc/tutorial_transportin....
Why does the serialization library have to include code from boost exception in order to do this?
You can use boost exception at the same place, catch the standard exception that the serialization throws, construct you're own boost exception and continue on.
No!!!! Misses the whole point - Boost.Exception allow you to annotate an existing exception without loosing the original information - and that includes the *type* of the original exception.
2) As others have already mentioned, Boost.Exception allows arbitrary exception objects to be cloned, amongst other things, this allows exceptions to propagate across threads. For example if a serialization routine is run as a future (quite a reasonable goal), then it would allow exceptions thrown during serialization in the worker thread, to be re-thrown in the calling thread when the result of the future is acquired. See http://www.boost.org/doc/libs/1_49_0/libs/exception/doc/tutorial_exception_p....
again the same question.
Consider writing a future - in order to preserve all the exception information, you would have to be able to catch, clone, and then rethrow *every possible exception type* that may be thrown by the code that the future calls. It is quite simply impossible. However, if all thrown exceptions inherit from boost::exception, then you simply catch that exception type, ask it to clone itself, and rethrow in a different thread. You preserve all the original error information, and crucially, all the original type information, even though the future doesn't itself know what the actual dynamic type of the caught and rethrown exception is. This actually looks compelling enough to me, that we should probably mandate use of BOOST_THROW_EXCEPTION.
For me, I've only used (3), but when you need it it's very useful. Both (1) and (2) look like killer use cases to me - not for you - for your users.
Let me be clear. I don't have any complaint about boost exception per se.
My complaint is the process by which it was inject.
Fair enough, but you're still 4 years too late on that one. I repeat an earlier question - if Boost.Exception were refactored to put the "core" exception throwing code either into boost/detail/ or indeed directly into boost/exception.hpp given that there's not much of it, would that address at least some of your concerns?
BUT - now you've sucked me into looking at the merits of including it, I don't see that it would be of any use. here's typical serialization code:
#include <boost/archiive/binary_iarchive.hpp> #include <ifstream> ... f(...){ ifsteam is("my file") binary_iarchive ia(is); try { my_data d; ia >> d; } catch(boost::archive::exception ae){ std::cout << ae.what(); throw(ae) ; // or throw something else } return; }
So if I want to use boost exception I would just write
#include <boost/archiive/binary_iarchive.hpp> #include <ifstream> #include <boost/exception/???.hpp> ...
f(...){ ifsteam is("my file") binary_iarchive ia(is); try { my_data d; ia >> d; } catch(boost::archive::exception ae){ std::cout << ae.what(); // I don't know how to use boost::exception insert your own code here boost::exception::throw(?) } return; }
I don't see injecting boost::exception into the serialization code changes this in any way
Please see my answers above. Now consider that the serialization code includes some use of Boost.Filesystem, Boost.Regex (filename parsing) and heaven known whatever other dependencies the object being [de]serialized depends on (presumably an object being deserialised could throw any exception Boost is capable of). If all those exception objects uniformly derive from boost::exception somewhere in their object hierarchy, then you catch *one* exception type, annotate it, and rethrow. All the original type information is retained, clients can catch the boost::exception and enumerate all the information it holds, or they can catch something more specific like boost::archive::exception and work from there. I admit to being new to what boost::exception has to offer, but that looks pretty compelling to me, Cheers, John.

John Maddock wrote:
Why does the serialization library have to include code from boost exception in order to do this?
You can use boost exception at the same place, catch the standard exception that the serialization throws, construct you're own boost exception and continue on.
No!!!!
Misses the whole point - Boost.Exception allow you to annotate an existing exception without loosing the original information - and that includes the *type* of the original exception.
Here is what I don't get. When the serialization code was written I decided that the exception mechanism was that right way to go. I realized that just a "generic" exeception wouldn't included enough information so I created boost::archive::exception and extra data specific the this kind of acception. The file name is archive_exception.hpp. This exception type has most of the useful information regarding the exception. Some was excluded as it would make the type "heavier" than I wanted or would have required data types which might use the heap or other resources which of course would be a disaster. It also was carefully designed not to include RTTI and other stuff which would make the library less attractive for lighter weight applications. Basically this was designed as the best balance among all the considerations I had to take into account - including the desire to pass as much information as possible to the application. I also used boost::throw_exception in order to permit the system to gracefully handle the case where exception were either not available or not permited in the user environment. boost::throw_exception was explicilty designed for this purpose and no other. So - boost::throw_except is changed and.... what? I already included all the useful information I can add. How can boost::throw_exception add to this on it's own? What can it possible do that's useful? The archive_exception is already derived from the standard base class so it can be caught by catch(std::exception e &). It's derived virtually from std::exception so the e in can be downcast to the archive_exception and get all it's data. If the user want's to, he has the option or using rtti type_id to get the type - but he's not forced to if he want's to keep his code lean and mean. To summarize, I don't see how just changing boost::throw_exception without changing anything else can possible add anything useful to the library or the users application.
Consider writing a future - in order to preserve all the exception information, you would have to be able to catch, clone, and then rethrow *every possible exception type* that may be thrown by the code that the future calls. It is quite simply impossible.
However, if all thrown exceptions inherit from boost::exception, then you simply catch that exception type, ask it to clone itself, and rethrow in a different thread. You preserve all the original error information, and crucially, all the original type information, even though the future doesn't itself know what the actual dynamic type of the caught and rethrown exception is.
Hmmm - I don't see how just changing the implementation of boost::throw_exception would change this in anyway. Perhaps you're suggesting that in addition to chaning the functionality of boost::throw the serialization libary should redefine archive_exception to derive from boost::exception rather directly from std::exception. Of course that's a totally different topic than we've been discussing up until now. and I guess would be a new thread. But maybe you're not suggesting that. Sorry if I got this wrong. Still, you're question obligated me to think a little about this. I would expect a library such as boost exception would have code along the following lines somewhere to be included/invoked from user code. void * x x = dynamic_cast<boost::exception be *>(std::current_exception()) if(0 != x){ ... // do great boost exception stuff } else { void * x = dynamic_cast<std::exception be *>(std::current_exception()); .. // use what() and do some stuff } else{ // handle the case where the library, user didn't bother to use std::exception } But this is totally compatible with the original implementation of boost::throw_exception! So it looks to me that changing the functionality of boost::throw adds nothing to libraries which don't use boost::exception. Even if libraries are changed to use THROW_BOOST_EXCEPTION the only thing added is file # / line # - I havn't heard any users clamoring for that. Finally, any users who want real information on the exception will have to include archive_exception.hpp in any case. True it make users think they are "handling" something - but if there's not catching archive_exception and dealing with the specifics, they might as well use std::exception. So I don't see that boost exception actually adds anything of any value.
This actually looks compelling enough to me, that we should probably mandate use of BOOST_THROW_EXCEPTION.
lol - right.
My complaint is the process by which it was inject. Fair enough, but you're still 4 years too late on that one.
lol - well I wasn't late when I brought it up the first time. It was right at release time when this bomb was dropped in at the last moment.
I repeat an earlier question - if Boost.Exception were refactored to put the "core" exception throwing code either into boost/detail/ or indeed directly into boost/exception.hpp given that there's not much of it, would that address at least some of your concerns?
I don't get this. Wouldn't this still drag in hundreds of lines of code that aren't being used?
BUT - now you've sucked me into looking at the merits of including it, I don't see that it would be of any use. here's typical serialization code:
#include <boost/archiive/binary_iarchive.hpp> #include <ifstream> ... f(...){ ifsteam is("my file") binary_iarchive ia(is); try { my_data d; ia >> d; } catch(boost::archive::exception ae){ std::cout << ae.what(); throw(ae) ; // or throw something else } return; }
So if I want to use boost exception I would just write
#include <boost/archiive/binary_iarchive.hpp> #include <ifstream> #include <boost/exception/???.hpp> ...
f(...){ ifsteam is("my file") binary_iarchive ia(is); try { my_data d; ia >> d; } catch(boost::archive::exception ae){ std::cout << ae.what(); // I don't know how to use boost::exception insert your own code here boost::exception::throw(?) } return; }
I don't see injecting boost::exception into the serialization code changes this in any way
Please see my answers above.
I still don't see how boost exception helps in my example. If you don't care about handling archive_exception you can just use ifsteam is("my file") binary_iarchive ia(is); my_data d; ia >> d; and just handle std::exception upstream. If you really like boost::exception your code when you eventually can eventually rethrow catch (std::exception e){ BOOST_EXCEPTION_THROW_EXCEPTION(e) }
Now consider that the serialization code includes some use of Boost.Filesystem, Boost.Regex (filename parsing) and heaven known whatever other dependencies the object being [de]serialized depends on (presumably an object being deserialised could throw any exception Boost is capable of). If all those exception objects uniformly derive from boost::exception somewhere in their object hierarchy, then you catch *one* exception type, annotate it, and rethrow. All the original type information is retained, clients can catch the boost::exception and enumerate all the information it holds, or they can catch something more specific like boost::archive::exception and work from there.
How is this different from using std::exception ?
I admit to being new to what boost::exception has to offer, but that looks pretty compelling to me,
Sorry john, I'm still not seeing it. You'll have to dumb it down for us mortals. Robert Ramey
Cheers, John.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

AMDG On 06/23/2012 12:11 PM, Robert Ramey wrote:
I also used boost::throw_exception in order to permit the system to gracefully handle the case where exception were either not available or not permited in the user environment. boost::throw_exception was explicilty designed for this purpose and no other.
This is the basic point of contention. According to those who favor the new version, boost::throw_exception is a hook to control the behavior of exceptions thrown by Boost libraries, and I think this is a perfectly reasonable interpretation. The original behavior was limited to two options: a) throw e; b) User defined boost::throw_exception(std::exception&) Boost.Exception added a third option: c) throw enable_current_exception(enable_error_info(x)) The important thing is that adding (c) didn't change the /interface/ of boost::throw_exception.
So - boost::throw_except is changed and.... what? I already included all the useful information I can add. How can boost::throw_exception add to this on it's own?
It can't. Boost.Exception allows /callers/ of your library to add their own information to the exception if they have more context than the Serialization library itself does.
However, if all thrown exceptions inherit from boost::exception, then you simply catch that exception type, ask it to clone itself, and rethrow in a different thread. You preserve all the original error information, and crucially, all the original type information, even though the future doesn't itself know what the actual dynamic type of the caught and rethrown exception is.
Hmmm - I don't see how just changing the implementation of boost::throw_exception would change this in anyway. Perhaps you're suggesting that in addition to chaning the functionality of boost::throw the serialization libary should redefine archive_exception to derive from boost::exception rather directly from std::exception. Of course that's a totally different topic than we've been discussing up until now. and I guess would be a new thread. But maybe you're not suggesting that. Sorry if I got this wrong.
Actually, inheriting from boost::exception doesn't work for this. To enable copying you have to throw using boost::enable_current_exception. try { throw enable_current_exception(x); } catch(...) { exception_ptr e = current_exception(); } // move e to another thread rethrow_exception(e);
Still, you're question obligated me to think a little about this. I would expect a library such as boost exception would have code along the following lines somewhere to be included/invoked from user code.
void * x x = dynamic_cast<boost::exception be *>(std::current_exception()) if(0 != x){ ... // do great boost exception stuff } else { void * x = dynamic_cast<std::exception be *>(std::current_exception()); .. // use what() and do some stuff } else{ // handle the case where the library, user didn't bother to use std::exception }
But this is totally compatible with the original implementation of boost::throw_exception!
Sure, but it also has nothing in particular to do with what Boost.Exception provides.
So it looks to me that changing the functionality of boost::throw adds nothing to libraries which don't use boost::exception.
You're looking at this the wrong way. It isn't necessarily the /library/ that uses Boost.Exception functionality. Whether Boost.Exception is useful depends on the users of the library. As such, it seems reasonable to allow users to decide whether they want to use Boost.Exception, which is exactly what happens if the library uses the current incarnation of boost::throw_exception.
I still don't see how boost exception helps in my example. If you don't care about handling archive_exception you can just use
ifsteam is("my file") binary_iarchive ia(is); my_data d; ia >> d;
and just handle std::exception upstream.
The code using Boost.Exception would look like: typedef boost::error_info< struct tag_archive_filename, std::string> archive_filename; ... try { ifstream is(filename); binary_archive ia(is); my_data d; ia >> d; } catch (boost::exception& e) { e << archive_filename(filename); throw; }
If you really like boost::exception your code when you eventually can eventually rethrow
catch (std::exception e){ BOOST_EXCEPTION_THROW_EXCEPTION(e) }
This of course loses the original type of the exception.
Now consider that the serialization code includes some use of Boost.Filesystem, Boost.Regex (filename parsing) and heaven known whatever other dependencies the object being [de]serialized depends on (presumably an object being deserialised could throw any exception Boost is capable of). If all those exception objects uniformly derive from boost::exception somewhere in their object hierarchy, then you catch *one* exception type, annotate it, and rethrow. All the original type information is retained, clients can catch the boost::exception and enumerate all the information it holds, or they can catch something more specific like boost::archive::exception and work from there.
How is this different from using std::exception ?
std::exception doesn't allow any addition annotation. Using std::exception, there's simply no way to add any additional information without either a) Knowing the type of the original exception, or b) Discarding all the type information of the original exception. In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
On 06/23/2012 12:11 PM, Robert Ramey wrote:
I also used boost::throw_exception in order to permit the system to gracefully handle the case where exception were either not available or not permited in the user environment. boost::throw_exception was explicilty designed for this purpose and no other.
This is the basic point of contention.
According to those who favor the new version, boost::throw_exception is a hook to control the behavior of exceptions thrown by Boost libraries, and I think this is a perfectly reasonable interpretation. The original behavior was limited to two options:
a) throw e; b) User defined boost::throw_exception(std::exception&)
Boost.Exception added a third option: c) throw enable_current_exception(enable_error_info(x))
The important thing is that adding (c) didn't change the /interface/ of boost::throw_exception.
agreed to all of the above.
So - boost::throw_except is changed and.... what? I already included all the useful information I can add. How can boost::throw_exception add to this on it's own?
It can't. Boost.Exception allows /callers/ of your library to add their own information to the exception if they have more context than the Serialization library itself does.
agreed - but one doesn't need boost.exception to do that.
However, if all thrown exceptions inherit from boost::exception, then you simply catch that exception type, ask it to clone itself, and rethrow in a different thread. You preserve all the original error information, and crucially, all the original type information, even though the future doesn't itself know what the actual dynamic type of the caught and rethrown exception is.
Hmmm - I don't see how just changing the implementation of boost::throw_exception would change this in anyway. Perhaps you're suggesting that in addition to chaning the functionality of boost::throw the serialization libary should redefine archive_exception to derive from boost::exception rather directly from std::exception. Of course that's a totally different topic than we've been discussing up until now. and I guess would be a new thread. But maybe you're not suggesting that. Sorry if I got this wrong.
Actually, inheriting from boost::exception doesn't work for this. To enable copying you have to throw using boost::enable_current_exception.
try { throw enable_current_exception(x); } catch(...) { exception_ptr e = current_exception(); } // move e to another thread rethrow_exception(e);
OK - get it - but I don't see that it adds any value compared to try { throw x; } catch(...){ exception_ptr e = std::current_exception(); std::rethrow_exception(e); // n3242 18.8} }
So it looks to me that changing the functionality of boost::throw adds nothing to libraries which don't use boost::exception.
You're looking at this the wrong way. It isn't necessarily the /library/ that uses Boost.Exception functionality.
agreed.
Whether Boost.Exception is useful depends on the users of the library.
agreed..
As such, it seems reasonable to allow users to decide whether they want to use Boost.Exception, which is exactly what happens if the library uses the current incarnation of boost::throw_exception.
A user can use all the useful features of boost exception just by just using a normal throw.
The code using Boost.Exception would look like:
typedef boost::error_info< struct tag_archive_filename, std::string> archive_filename; ...
try { ifstream is(filename); binary_archive ia(is); my_data d; ia >> d; } catch (boost::exception& e) { e << archive_filename(filename); throw; }
lol - now you've thrown away all the information in archive_exception! Use this instead. try { ifstream is(filename); binary_archive ia(is); my_data d; ia >> d; } catch (boost::archive::exception& ae) { // assuming you love boost exception boost::exception e(ae); ae << archive_filename(filename); throw(ae); } catch(std::exception & se){ // special sauce for standard library exceptions throw ... } Nothing in this requires any special help from boost::throw_exception. It's all in he user's program.
If you really like boost::exception your code when you eventually can eventually rethrow
catch (std::exception e){ BOOST_EXCEPTION_THROW_EXCEPTION(e) }
This of course loses the original type of the exception.
I don't think that's true. It's not clear to me from the documentation. I get this idea from looking at the code. Of course if it were true it would be huge blunder in the design of the library.
How is this different from using std::exception ?
std::exception doesn't allow any addition annotation. Using std::exception, there's simply no way to add any additional information without either a) Knowing the type of the original exception, or b) Discarding all the type information of the original exception.
A user can create an object at the catch site to add any information he wants. He can do this using boost exception if he wants or any other system he prefers. This doesn't require any thing special from the throw site. That is, there is no reason not to use anything but simple throw which of course is the original definition of boost::throw_exception. Robert Ramey
In Christ, Steven Watanabe
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 23/06/2012 18:25, Robert Ramey wrote:
Steven Watanabe wrote:
Actually, inheriting from boost::exception doesn't work for this. To enable copying you have to throw using boost::enable_current_exception.
try { throw enable_current_exception(x); } catch(...) { exception_ptr e = current_exception(); } // move e to another thread rethrow_exception(e);
OK - get it - but I don't see that it adds any value compared to
try { throw x; } catch(...){ exception_ptr e = std::current_exception(); std::rethrow_exception(e); // n3242 18.8} }
Would you happen to know which compilers implement n3242 already? Boost.Exception works for me with the compilers I use everyday, as long as the original exception was thrown with enable_current_exception.
The code using Boost.Exception would look like:
typedef boost::error_info< struct tag_archive_filename, std::string> archive_filename; ...
try { ifstream is(filename); binary_archive ia(is); my_data d; ia >> d; } catch (boost::exception& e) { e << archive_filename(filename); throw; }
lol - now you've thrown away all the information in archive_exception! Use this instead.
Most certainly not, the **type** of the original exception is not lost when using boost::throw_exception. In this case, e is still an archive_exception.
If you really like boost::exception your code when you eventually can eventually rethrow
catch (std::exception e){ BOOST_EXCEPTION_THROW_EXCEPTION(e) }
This of course loses the original type of the exception.
I don't think that's true. It's not clear to me from the documentation. I get this idea from looking at the code. Of course if it were true it would be huge blunder in the design of the library.
Wouldn't that just throw a sliced copy of the exception, a new exception of type std::exception, instead of rethrowing the original exception? Agustín K-ballo Bergé.-

Agustín K-ballo Bergé wrote:
On 23/06/2012 18:25, Robert Ramey wrote:
Steven Watanabe wrote:
Actually, inheriting from boost::exception doesn't work for this. To enable copying you have to throw using boost::enable_current_exception.
try { throw enable_current_exception(x); } catch(...) { exception_ptr e = current_exception(); } // move e to another thread rethrow_exception(e);
OK - get it - but I don't see that it adds any value compared to
try { throw x; } catch(...){ exception_ptr e = std::current_exception(); std::rethrow_exception(e); // n3242 18.8} }
Would you happen to know which compilers implement n3242 already? Boost.Exception works for me with the compilers I use everyday, as long as the original exception was thrown with enable_current_exception.
hmm - I really don't know. It looks like boost exception implements this functionality for those compilers which don't have it. Actually this is really good thing in my opinion. If this were a separate library part of the boost directory/namespace I think it would be good addition. But this facility is included in the same library as another facility useful to users. So addressing of one problem - non-conforming compilers is not orthogonal to the other problem - helpful facilities for users. It's not fine grained enough for my taste. Robert Ramey

On 23/06/2012 20:33, Robert Ramey wrote:
But this facility is included in the same library as another facility useful to users. So addressing of one problem - non-conforming compilers is not orthogonal to the other problem - helpful facilities for users. It's not fine grained enough for my taste.
At that we agree, I never use the arbitrary data transport facilities of Boost.Exception myself when I write library code. I think of that facility as a end-user only kind of facility, but its still nice that the users of my library can leverage it if they want to (and I do use it when I myself am the user of my library). I wouldn't know if its either possible or sensible to implement the two features as separate components, perhaps its something worth researching. Regarding the overhead payed for something that I may not want to use, according to Boost.Exception documentation is negligible. For me negligible its usually too much, but if we are talking exceptions then we are talking about exceptional situations (yes, I'm one of those purists). The documentation for the library states: The cost of this integration is: - In terms of space: a pointer and 3 ints are added to the static size of exception objects. - In terms of speed: the pointer is initialized to null at the point of the throw. - In terms of coupling: about 400 self-contained lines of C++ with no external includes. at http://www.boost.org/doc/libs/1_49_0/libs/exception/doc/frequently_asked_que... . It's placed as an answer to "Why is boost::exception integrated in boost::throw_exception?" rather than "What is the space overhead of the boost::exception base class?" which is a bit unfortunate. I don't see html anchors to each of the questions either, sorry about that. Agustín K-ballo Bergé.-

AMDG On 06/23/2012 04:33 PM, Robert Ramey wrote:
Agustín K-ballo Bergé wrote:
Would you happen to know which compilers implement n3242 already? Boost.Exception works for me with the compilers I use everyday, as long as the original exception was thrown with enable_current_exception.
hmm - I really don't know. It looks like boost exception implements this functionality for those compilers which don't have it. Actually this is really good thing in my opinion. If this were a separate library part of the boost directory/namespace I think it would be good addition.
But this facility is included in the same library as another facility useful to users. So addressing of one problem - non-conforming compilers is not orthogonal to the other problem - helpful facilities for users. It's not fine grained enough for my taste.
Sure it is. There are three separate pieces: 1) throw boost::enable_error_info(e) adds boost::exception. 2) throw boost::enable_current_exception(e) adds the information needed for boost::current_exception. 3) boost::throw_exception is implemented in terms of both (1) and (2). In Christ, Steven Watanabe

On 24.06.2012, at 01:33, Robert Ramey wrote:
But this facility is included in the same library as another facility useful to users. So addressing of one problem - non-conforming compilers is not orthogonal to the other problem - helpful facilities for users. It's not fine grained enough for my taste.
They're not non-conforming. They're just not C++11-enabled. There's a big difference. Sebastian

AMDG On 06/23/2012 02:25 PM, Robert Ramey wrote:
Steven Watanabe wrote:
So - boost::throw_except is changed and.... what? I already included all the useful information I can add. How can boost::throw_exception add to this on it's own? It can't. Boost.Exception allows /callers/ of your library to add their own information to the exception if they have more context than the Serialization library itself does.
agreed - but one doesn't need boost.exception to do that.
It isn't strictly necessary, but it makes things a lot easier.
try { throw enable_current_exception(x); } catch(...) { exception_ptr e = current_exception(); } // move e to another thread rethrow_exception(e);
OK - get it - but I don't see that it adds any value compared to
try { throw x; } catch(...){ exception_ptr e = std::current_exception(); std::rethrow_exception(e); // n3242 18.8} }
It doesn't. For compilers that support std::current_exception, boost::enable_current_exception can be a no-op.
The code using Boost.Exception would look like: typedef boost::error_info< struct tag_archive_filename, std::string> archive_filename; ...
try { ifstream is(filename); binary_archive ia(is); my_data d; ia >> d; } catch (boost::exception& e) { e << archive_filename(filename); throw; }
lol - now you've thrown away all the information in archive_exception!
Nope. throw without an argument rethrows the original exception object.
Use this instead.
try { ifstream is(filename); binary_archive ia(is); my_data d; ia >> d; } catch (boost::archive::exception& ae) { // assuming you love boost exception boost::exception e(ae); ae << archive_filename(filename); throw(ae); } catch(std::exception & se){ // special sauce for standard library exceptions throw ... }
Nothing in this requires any special help from boost::throw_exception. It's all in he user's program.
To make this work you have to enumerate all the possible exception types that you might have to deal with. You may not even know all the possible exception types. Also, knowing that you have something that derives from std::exception isn't enough. To preserve all information, you have to know the full dynamic type of the exception.
If you really like boost::exception your code when you eventually can eventually rethrow
catch (std::exception e){ BOOST_EXCEPTION_THROW_EXCEPTION(e) }
This of course loses the original type of the exception.
I don't think that's true. It's not clear to me from the documentation. I get this idea from looking at the code. Of course if it were true it would be huge blunder in the design of the library.
If you throw something with a static type of std::exception, it's simply not possible to know what its dynamic type is. A throw with no argument can preserve the original exception, but there's no way to use "throw;" to inject Boost.Exception.
How is this different from using std::exception ?
std::exception doesn't allow any addition annotation. Using std::exception, there's simply no way to add any additional information without either a) Knowing the type of the original exception, or b) Discarding all the type information of the original exception.
A user can create an object at the catch site to add any information he wants. He can do this using boost exception if he wants or any other system he prefers. This doesn't require any thing special from the throw site. That is, there is no reason not to use anything but simple throw which of course is the original definition of boost::throw_exception.
You're ignoring my point. Would you mind explaining how to avoid both (a) and (b)? Or pick one and explain why you think it isn't a problem? As I see it, (a) is extremely verbose if there are multiple possible exception types, and (b) can obviously lose important information. In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
std::exception doesn't allow any addition annotation. Using std::exception, there's simply no way to add any additional information without either a) Knowing the type of the original exception, or b) Discarding all the type information of the original exception.
You're ignoring my point. Would you mind explaining how to avoid both (a) and (b)? Or pick one and explain why you think it isn't a problem? As I see it, (a) is extremely verbose if there are multiple possible exception types, and (b) can obviously lose important information.
OK I was a little too hasty in my response. In my last response to Emil I reworked my example more carefully, feel free to comment on that. Robert Ramey
In Christ, Steven Watanabe
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Jun 23, 2012, at 3:11 PM, Robert Ramey wrote:
To summarize, I don't see how just changing boost::throw_exception without changing anything else can possible add anything useful to the library or the users application. [...] Hmmm - I don't see how just changing the implementation of boost::throw_exception would change this in anyway. Perhaps you're suggesting that in addition to chaning the functionality of boost::throw the serialization libary should redefine archive_exception to derive from boost::exception rather directly from std::exception. Of course that's a totally different topic than we've been discussing up until now. and I guess would be a new thread. But maybe you're not suggesting that. Sorry if I got this wrong.
This is incorrect. boost::throw_exception (in the interesting case, where BOOST_NO_EXCEPTIONS and BOOST_EXCEPTION_DISABLE are both undefined) ensures that the thrown object is derived from boost::exception even if the argument is not. It does this (via enable_error_info(), which does the heavy lifting) by examining the type E of the argument. If E is derived from boost::exception, then just use the argument as is. Otherwise, construct a new object. The class of the new object derives from both E and boost::exception (multiple inheritance), and has a conversion constructor for arguments of type E which passes the argument to the new class's base E object's copy constructor. Apply that constructor to the original argument, and use the resulting object. (Note that throw requires the argument to be copy constructible, so the described mechanism imposes no new constraint on E by requiring copy construction.) None of this *requires* any intervention by calling code or library authors. There is no requirement to explicitly derive from boost::exception for this to work. A library developer might choose to derive an exception class from boost::exception, since that will simplify the resulting generated code and eliminate a copy construction in invocations of boost::throw_exception, but one gets a boost::exception based object regardless of what came in. [Note that boost::exception is *not* derived from std::exception; it is a "mixin" class that is typically derived from by multiple inheritance.]

Kim Barrett wrote:
boost::throw_exception (in the interesting case, where BOOST_NO_EXCEPTIONS and BOOST_EXCEPTION_DISABLE are both undefined) ensures that the thrown object is derived from boost::exception even if the argument is not. It does this (via enable_error_info(), which does the heavy lifting) by examining the type E of the argument. If E is derived from boost::exception, then just use the argument as is. Otherwise, construct a new object. The class of the new object derives from both E and boost::exception (multiple inheritance), and has a conversion constructor for arguments of type E which passes the argument to the new class's base E object's copy constructor. Apply that constructor to the original argument, and use the resulting object. (Note that throw requires the argument to be copy constructible, so the described mechanism imposes no new constraint on E by requiring copy construction.)
So any boost library which previously used boost::throw exception with an exception which was non-copyable would break? I guess we're lucky no one did that. thanks for explaining this. I would never have figured it without spending a lot of time. Robert Ramey

On 23/06/2012 19:24, Robert Ramey wrote:
Kim Barrett wrote:
boost::throw_exception (in the interesting case, where BOOST_NO_EXCEPTIONS and BOOST_EXCEPTION_DISABLE are both undefined) ensures that the thrown object is derived from boost::exception even if the argument is not. (...) (Note that throw requires the argument to be copy constructible, so the described mechanism imposes no new constraint on E by requiring copy construction.)
So any boost library which previously used boost::throw exception with an exception which was non-copyable would break? I guess we're lucky no one did that.
Anyone throwing anything by means of throw that isn't copyable would break. This is a standard requirement, not a boost::throw_exception one. Reading from n3376 at [except.throw] 15.1.3: A throw-expression copy-initializes (8.5) a temporary object, called the exception object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throwand adjusting the type from “array of T” or “function returning T” to “pointer to T” or “pointer to function returning T”, respectively. The temporary is an lvalue and is used to initialize the variable named in the matching handler (15.3). If the type of the exception object would be an incomplete type or a pointer to an incomplete type other than (possibly cv-qualified) voidthe program is ill-formed. Except for these restrictions and the restrictions on type matching mentioned in15.3, the operand of throwis treated exactly as a function argument in a call (5.2.2) or the operand of a return statement. Agustín K-ballo Bergé.-

AMDG On 06/23/2012 03:24 PM, Robert Ramey wrote:
Kim Barrett wrote:
(Note that throw requires the argument to be copy constructible, so the described mechanism imposes no new constraint on E by requiring copy construction.)
So any boost library which previously used boost::throw exception with an exception which was non-copyable would break? I guess we're lucky no one did that.
As Kim noted above, this requirement isn't imposed by boost::throw_exception. It's imposed by the C++ langauge. C++11 15.1p5: "When the thrown object is a class object, the copy/move constructor and the destructor shall be accessible, even if the copy/move operation is elided"
thanks for explaining this. I would never have figured it without spending a lot of time.
In Christ, Steven Watanabe

On Sat, Jun 23, 2012 at 3:24 PM, Robert Ramey <ramey@rrsd.com> wrote:
Kim Barrett wrote:
boost::throw_exception (in the interesting case, where BOOST_NO_EXCEPTIONS and BOOST_EXCEPTION_DISABLE are both undefined) ensures that the thrown object is derived from boost::exception even if the argument is not. It does this (via enable_error_info(), which does the heavy lifting) by examining the type E of the argument. If E is derived from boost::exception, then just use the argument as is. Otherwise, construct a new object. The class of the new object derives from both E and boost::exception (multiple inheritance), and has a conversion constructor for arguments of type E which passes the argument to the new class's base E object's copy constructor. Apply that constructor to the original argument, and use the resulting object. (Note that throw requires the argument to be copy constructible, so the described mechanism imposes no new constraint on E by requiring copy construction.)
So any boost library which previously used boost::throw exception with an exception which was non-copyable would break? I guess we're lucky no one did that.
FYI the C++ standard requires that exception types must have accessible, no-throw copy constructor. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

on Sat Jun 23 2012, "Robert Ramey" <ramey-AT-rrsd.com> wrote:
If you really like boost::exception your code when you eventually can eventually rethrow
catch (std::exception e){ BOOST_EXCEPTION_THROW_EXCEPTION(e) }
IIUC, even if you change it to catch by reference, as you should, and even if std::exception weren't an abstract base class, which it is, that approach will slice the caught exception and lose all the information thrown with it. BOOST_EXCEPTION_THROW_EXCEPTION needs to copy the exception object into this type it builds with multiple inheritance from boost::exception, and it needs to do this with full knowledge of the static type of the exception being thrown. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

Dave Abrahams wrote:
on Sat Jun 23 2012, "Robert Ramey" <ramey-AT-rrsd.com> wrote:
If you really like boost::exception your code when you eventually can eventually rethrow
catch (std::exception & e){ // not additon of & BOOST_THROW_EXCEPTION(e) }
IIUC, even if you change it to catch by reference, as you should, and even if std::exception weren't an abstract base class, which it is, that approach will slice the caught exception and lose all the information thrown with it. BOOST_EXCEPTION_THROW_EXCEPTION needs to copy the exception object into this type it builds with multiple inheritance from boost::exception, and it needs to do this with full knowledge of the static type of the exception being thrown.
wow I overlooked this. So in our case, if e was reference to an instance of a boost::archive::archive_exception object which holds all the interesting data, this information would be thrown away along with the actual type of the exception? That's terrible. Robert Ramey

on Sat Jun 23 2012, "Robert Ramey" <ramey-AT-rrsd.com> wrote:
Dave Abrahams wrote:
on Sat Jun 23 2012, "Robert Ramey" <ramey-AT-rrsd.com> wrote:
If you really like boost::exception your code when you eventually can eventually rethrow
catch (std::exception & e){ // not additon of & BOOST_THROW_EXCEPTION(e) }
IIUC, even if you change it to catch by reference, as you should, and even if std::exception weren't an abstract base class, which it is, that approach will slice the caught exception and lose all the information thrown with it. BOOST_EXCEPTION_THROW_EXCEPTION needs to copy the exception object into this type it builds with multiple inheritance from boost::exception, and it needs to do this with full knowledge of the static type of the exception being thrown.
wow I overlooked this.
So in our case, if e was reference to an instance of a boost::archive::archive_exception object which holds all the interesting data, this information would be thrown away along with the actual type of the exception? That's terrible.
Like some other things we've discussed, that's essentially a C++ language feature. You couldn't do a plain "throw e" either, without causing the slice. The only way to propagate the contents of e is "throw;", which is obviously incapable of enhancing the thrown exception in any way. The the more you pick at Emil's design and the more I check your arguments, the more impressed I am with the care he took. I may be misunderstanding, but IIUC, the "problem" that he "fixed" was that his change caused already-unsupported misuses of boost::throw_exception to stop compiling. It's arguable that those misuses *should* be flagged with compiler errors. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

Dave Abrahams wrote:
on Sat Jun 23 2012, "Robert Ramey" <ramey-AT-rrsd.com> wrote:
Like some other things we've discussed, that's essentially a C++ language feature. You couldn't do a plain "throw e" either, without causing the slice. The only way to propagate the contents of e is "throw;", which is obviously incapable of enhancing the thrown exception in any way.
The the more you pick at Emil's design and the more I check your arguments, the more impressed I am with the care he took.
My reaction is just the opposite even little things are a problem, The first thing I looked at was the documentation of BOOST_THROW_EXCEPTION(e). If this is invoked at the exception site it works. If it is invoked anywhere else - like a rethrow it doesn't. It's totally non-intuitive and a trap for users. There is no mention of this in the documentation. And of course the whole idea that to gain benefit of a library one has to change the code of all the other libraries that the application might use is a big problem for me. The fact that the author doesn't think this is a problem is a very strong suggestion to me that I'd find the library problematic to actually use. And this is even before I've really even looked at it. I've more than a little skeptical. And I believe that a solution could have been crafted to avoid the issues that I've raised but that Emil doesn't agree that these concerns are legimate. I know steve doesn't agree with me on this either. So now I would have to provide a counter example which means basically re-doing the original work in the right way as I see it.
I may be misunderstanding, but IIUC, the "problem" that he "fixed" was that his change caused already-unsupported misuses of boost::throw_exception to stop compiling. It's arguable that those misuses *should* be flagged with compiler errors.
the original boost::throw_exception was defined as: #ifdef BOOST_NO_EXCEPTIONS void throw_exception( std::exception const & e ); // user defined #else template<class E> void throw_exception(E const & e){ throw(e); } #endif it's hard to see how one could even define "misuse" of this - much less detect it. Robert Ramey

On 24/06/2012 2:40, Robert Ramey wrote:
Dave Abrahams wrote:
on Sat Jun 23 2012, "Robert Ramey" <ramey-AT-rrsd.com> wrote:
Like some other things we've discussed, that's essentially a C++ language feature. You couldn't do a plain "throw e" either, without causing the slice. The only way to propagate the contents of e is "throw;", which is obviously incapable of enhancing the thrown exception in any way.
The the more you pick at Emil's design and the more I check your arguments, the more impressed I am with the care he took.
My reaction is just the opposite
even little things are a problem, The first thing I looked at was the documentation of BOOST_THROW_EXCEPTION(e).
If this is invoked at the exception site it works. If it is invoked anywhere else - like a rethrow it doesn't. It's totally non-intuitive and a trap for users. There is no mention of this in the documentation.
This is the nature of C++ exceptions, it is no different for simply `throw e;`. It may be non-intuitive for those not versed in C++ exceptions (they are far more complex than they appear), and its certainly a trap for users but such trap comes from the standard and not from Boost.Exception.
I may be misunderstanding, but IIUC, the "problem" that he "fixed" was that his change caused already-unsupported misuses of boost::throw_exception to stop compiling. It's arguable that those misuses *should* be flagged with compiler errors.
the original boost::throw_exception was defined as:
#ifdef BOOST_NO_EXCEPTIONS void throw_exception( std::exception const & e ); // user defined #else template<class E> void throw_exception(E const & e){ throw(e); } #endif
it's hard to see how one could even define "misuse" of this - much less detect it.
As it was previously stated, the misuses of boost:throw_exception where those that didn't pass an exception derived from std::exception. They would fail when BOOST_NO_EXCEPTIONS was defined, they fail all the time now. Agustín K-ballo Bergé.-

on Sun Jun 24 2012, "Robert Ramey" <ramey-AT-rrsd.com> wrote:
Dave Abrahams wrote:
on Sat Jun 23 2012, "Robert Ramey" <ramey-AT-rrsd.com> wrote:
Like some other things we've discussed, that's essentially a C++ language feature. You couldn't do a plain "throw e" either, without causing the slice. The only way to propagate the contents of e is "throw;", which is obviously incapable of enhancing the thrown exception in any way.
The the more you pick at Emil's design and the more I check your arguments, the more impressed I am with the care he took.
My reaction is just the opposite
even little things are a problem, The first thing I looked at was the documentation of BOOST_THROW_EXCEPTION(e).
If this is invoked at the exception site it works. If it is invoked anywhere else - like a rethrow it doesn't.
IMO it is unreasonable to expect "BOOST_THROW_EXCEPTION(e)" to work better in this regard than "throw e" does. As I wrote above, they have the exact same issue.
It's totally non-intuitive and a trap for users.
IMO it's totally intuitive for BOOST_THROW_EXCEPTION to follow the pattern set by "throw." Of course it would be nice if the library facility could be somehow more forgiving of ignorance and misuse than "throw" is, but, well, it can't.
There is no mention of this in the documentation.
With all due respect, from the foregoing discussion it is plain that there are a few fairly basic things about the behavior of C++ exceptions that you didn't understand, and that lack of understanding has colored your expectations of the library. You also expected "throw e" to be non-slicing. It might be very nice if the library documentation included a tutorial on these issues, but it's unreasonable to treat it as a defect in the library.
And of course the whole idea that to gain benefit of a library one has to change the code of all the other libraries that the application might use is a big problem for me.
I agree absolutely. The C++ language should make it more natural and MUCH less intrusive to do this stuff. There's always a balancing act when you have to decide whether to proceed with implementing something that cuts across the grain of the language. Sometimes it's not worth the cost. As these sorts of things go, this one has a fairly low cost, but it's not free.
The fact that the author doesn't think this is a problem is a very strong suggestion to me that I'd find the library problematic to actually use.
It's understandable that you'd take issue with the author's attitude toward your objections. However, I think part of the problem, for which you might consider taking responsibility, is that your reaction to the issue has been somewhat... intemperate and overbroad. That tends to make other people dismissive ("he *can't* be serious!"), and with that, any legitimate concerns tend to get swept aside.
And this is even before I've really even looked at it. I've more than a little skeptical.
Quite clearly.
And I believe that a solution could have been crafted to avoid the issues that I've raised but that Emil doesn't agree that these concerns are legimate. I know steve doesn't agree with me on this either.
Wait; there are two separate things: 1. Are your concerns legitimate? 2. Is there a design that avoids these issues? I've seen lots of argument about #2, but not much about #1. I haven't read everything that Emil has posted, but Steven in particular has stuck closely to the technical stuff (#2). Re: #2, I don't see how there can be a substantially better design for this facility either, at least with C++ as it exists today.
So now I would have to provide a counter example which means basically re-doing the original work in the right way as I see it.
Unfortunately, yes. There's no other way to support your claim about #2.
I may be misunderstanding, but IIUC, the "problem" that he "fixed" was that his change caused already-unsupported misuses of boost::throw_exception to stop compiling. It's arguable that those misuses *should* be flagged with compiler errors.
the original boost::throw_exception was defined as:
#ifdef BOOST_NO_EXCEPTIONS void throw_exception( std::exception const & e ); // user defined #else template<class E> void throw_exception(E const & e){ throw(e); } #endif
it's hard to see how one could even define "misuse" of this - much less detect it.
It's trivial: boost::throw_exception(1) you detect it by setting BOOST_NO_EXCEPTIONS, which causes the code to stop compiling. A reasonable rewrite of the original boost::throw_exception that does this detection without adding any new functionality might be: #ifdef BOOST_NO_EXCEPTIONS void throw_exception( std::exception const & e ); // user defined #else template<class E> void throw_exception(E const & e){ std::exception const& must_be_a_std_exception = e; // <=== NEW throw(e); } #endif Arguably it would have gone more smoothly for Emil had he done this, then waited a while (a whole release cycle?), and then implemented his changes. Then nobody would have been able to complain that Boost.Exception broke their code. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Sat, Jun 23, 2012 at 10:40 PM, Robert Ramey <ramey@rrsd.com> wrote:
If this is invoked at the exception site it works. If it is invoked anywhere else - like a rethrow it doesn't. It's totally non-intuitive and a trap for users. There is no mention of this in the documentation.
The danger of slicing in C++ is beyond the scope of any Boost library documentation. That said, Boost Exception does protect the user from slicing boost::exception objects.
And I believe that a solution could have been crafted to avoid the issues that I've raised but that Emil doesn't agree that these concerns are legimate. I know steve doesn't agree with me on this either.
The concerns are legitimate, the disagreement is over the conclusion you've reached. You're yet to back your beliefs with facts.
So now I would have to provide a counter example which means basically re-doing the original work in the right way as I see it.
A lot of time got wasted in this discussion explaining why your ideas don't work. Producing a working piece of code would be a welcome change, I think.
I may be misunderstanding, but IIUC, the "problem" that he "fixed" was that his change caused already-unsupported misuses of boost::throw_exception to stop compiling. It's arguable that those misuses *should* be flagged with compiler errors.
the original boost::throw_exception was defined as:
#ifdef BOOST_NO_EXCEPTIONS void throw_exception( std::exception const & e ); // user defined #else template<class E> void throw_exception(E const & e){ throw(e); } #endif
it's hard to see how one could even define "misuse" of this - much less detect it.
You should try to see it though. Several people have pointed it out. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Sat, Jun 23, 2012 at 6:50 PM, Dave Abrahams <dave@boostpro.com> wrote:
The the more you pick at Emil's design and the more I check your arguments, the more impressed I am with the care he took. I may be misunderstanding, but IIUC, the "problem" that he "fixed" was that his change caused already-unsupported misuses of boost::throw_exception to stop compiling. It's arguable that those misuses *should* be flagged with compiler errors.
No, those were good compiler errors. The problem I caused was because I made what I thought was a reasonable assumption: that people who enable exception handling won't disable RTTI (AFAIK this only applies to MSVC, other compilers depend on RTTI to implement exception handling.) Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

on Sun Jun 24 2012, Emil Dotchevski <emildotchevski-AT-gmail.com> wrote:
On Sat, Jun 23, 2012 at 6:50 PM, Dave Abrahams <dave@boostpro.com> wrote:
The the more you pick at Emil's design and the more I check your arguments, the more impressed I am with the care he took. I may be misunderstanding, but IIUC, the "problem" that he "fixed" was that his change caused already-unsupported misuses of boost::throw_exception to stop compiling. It's arguable that those misuses *should* be flagged with compiler errors.
No, those were good compiler errors.
I don't know what you mean by "good" here.
The problem I caused was because I made what I thought was a reasonable assumption: that people who enable exception handling won't disable RTTI
Ah, that is a different issue than the one I supposed it to be. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Sun, Jun 24, 2012 at 7:13 AM, Dave Abrahams <dave@boostpro.com> wrote:
on Sun Jun 24 2012, Emil Dotchevski <emildotchevski-AT-gmail.com> wrote:
On Sat, Jun 23, 2012 at 6:50 PM, Dave Abrahams <dave@boostpro.com> wrote:
The the more you pick at Emil's design and the more I check your arguments, the more impressed I am with the care he took. I may be misunderstanding, but IIUC, the "problem" that he "fixed" was that his change caused already-unsupported misuses of boost::throw_exception to stop compiling. It's arguable that those misuses *should* be flagged with compiler errors.
No, those were good compiler errors.
I don't know what you mean by "good" here.
I mean the compile error that the current boost::throw_exception induces if the type of the passed object doesn't derive from std::exception is good, even though it "broke" non-conforming libraries. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

on Sun Jun 24 2012, Emil Dotchevski <emildotchevski-AT-gmail.com> wrote:
On Sun, Jun 24, 2012 at 7:13 AM, Dave Abrahams <dave@boostpro.com> wrote:
on Sun Jun 24 2012, Emil Dotchevski <emildotchevski-AT-gmail.com> wrote:
On Sat, Jun 23, 2012 at 6:50 PM, Dave Abrahams <dave@boostpro.com> wrote:
The the more you pick at Emil's design and the more I check your arguments, the more impressed I am with the care he took. I may be misunderstanding, but IIUC, the "problem" that he "fixed" was that his change caused already-unsupported misuses of boost::throw_exception to stop compiling. It's arguable that those misuses *should* be flagged with compiler errors.
No, those were good compiler errors.
I don't know what you mean by "good" here.
I mean the compile error that the current boost::throw_exception induces if the type of the passed object doesn't derive from std::exception is good, even though it "broke" non-conforming libraries.
I think you're agreeing with me, then, despite the fact that you started with "No..." -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Sun, Jun 24, 2012 at 4:21 PM, Dave Abrahams <dave@boostpro.com> wrote:
I think you're agreeing with me, then, despite the fact that you started with "No..."
Yes! Sorry. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Sat, Jun 23, 2012 at 12:11 PM, Robert Ramey <ramey@rrsd.com> wrote:
John Maddock wrote:
Why does the serialization library have to include code from boost exception in order to do this?
You can use boost exception at the same place, catch the standard exception that the serialization throws, construct you're own boost exception and continue on.
No!!!!
Misses the whole point - Boost.Exception allow you to annotate an existing exception without loosing the original information - and that includes the *type* of the original exception.
Here is what I don't get.
When the serialization code was written I decided that the exception mechanism was that right way to go. I realized that just a "generic" exeception wouldn't included enough information so I created boost::archive::exception and extra data specific the this kind of acception. The file name is archive_exception.hpp. This exception type has most of the useful information regarding the exception.
That's fine.
Some was excluded as it would make the type "heavier" than I wanted or would have required data types which might use the heap or other resources which of course would be a disaster.
Calling boost::throw_exception doesn't allocate anything from the heap. That said, it's not a problem to attach heap-allocated data to exception objects. Note that many compilers allocate the exception objects from the heap anyway.
So - boost::throw_except is changed and.... what? I already included all the useful information I can add. How can boost::throw_exception add to this on it's own? What can it possible do that's useful?
For example, if Boost Serialization calls boost::throw_exception, an application that serializes data that comes from a web site could store the web address, the user name, port number, or whatever else the application needs to handle the exception.
If the user want's to, he has the option or using rtti type_id to get the type - but he's not forced to if he want's to keep his code lean and mean.
For 100th time, boost::throw_exception works with RTTI off.
your code when you eventually can eventually rethrow
catch (std::exception e){ BOOST_EXCEPTION_THROW_EXCEPTION(e) }
There are two problems with this code. First, the catch as written slices, erasing the dynamic type of the exception. You should never catch exceptions by value. Second, even if you catch std::exception & obj, throwing obj will slice, erasing the dynamic type of the original exception. If the point of this catch is to translate the type of the exception object, it has to look like: catch( foo & e ) { BOOST_THROW_EXCEPTION(my_foo(e)); } catch( bar & e ) { BOOST_THROW_EXCEPTION(my_bar(e)); } catch( foobar & e ) { BOOST_THROW_EXCEPTION(my_foobar(e)); } catch( ... ) { assert(0); } And of course this nonsense has to go around every call to Boost Serialization. WHY?
Now consider that the serialization code includes some use of
Boost.Filesystem, Boost.Regex (filename parsing) and heaven known whatever other dependencies the object being [de]serialized depends on (presumably an object being deserialised could throw any exception Boost is capable of). If all those exception objects uniformly derive from boost::exception somewhere in their object hierarchy, then you catch *one* exception type, annotate it, and rethrow. All the original type information is retained, clients can catch the boost::exception and enumerate all the information it holds, or they can catch something more specific like boost::archive::exception and work from there.
How is this different from using std::exception ?
You can't add your own stuff to a live std::exception. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Emil Dotchevski wrote:
On Sat, Jun 23, 2012 at 12:11 PM, Robert Ramey <ramey@rrsd.com> wrote:
For example, if Boost Serialization calls boost::throw_exception, an application that serializes data that comes from a web site could store the web address, the user name, port number, or whatever else the application needs to handle the exception.
the serialization libary will likely not have this information. Geneally the serilalizaiton library uses some sort of stream i/o object. Many times errors are detected in the stream. At this point, the none of the library knows what the file name is so it can't be added in until some way higher level. The current archive_exception class holds all the useful information which is available.
your code when you eventually can eventually rethrow
catch (std::exception e){ BOOST_EXCEPTION_THROW_EXCEPTION(e) }
Second, even if you catch std::exception & obj, throwing obj will slice, erasing the dynamic type of the original exception.
It's hard to see the slicing through the macro isn't the standard way of handling this better? catch(std::exception & e){ std::exception_ptr e = std::current_exception(); std::rethrow_exception(e); } or if you want to add your own sauce catch(std::exception &e){ std::exception_ptr e = std::current_exception(); someclass se(e, extra stuff); // home brew or from some library std::throw(se); } or if you want to catch anyone's stuff catch(...){ std::exception_ptr e = std::current_exception(); my_unknown_exception me(e); // though its not clear what the upper level could do with this } this would confine the usage of boost exception to areas where the user can decide whether or not he want's to use it. It looks to me that the standard was conceived to support just this usage. It doesn't require anything special at the throw point. The standard facility of using one's own exception class is sufficient.
If the point of this catch is to translate the type of the exception object, it has to look like:
catch( foo & e ) { BOOST_THROW_EXCEPTION(my_foo(e)); } catch( bar & e ) { BOOST_THROW_EXCEPTION(my_bar(e)); } catch( foobar & e ) { BOOST_THROW_EXCEPTION(my_foobar(e)); } catch( ... ) { assert(0); }
And of course this nonsense has to go around every call to Boost Serialization.
WHY?
lol - well you've got a point here. But I not convinced a huge problem in practice. I would expect most of these would be placed at the much higer levels.
How is this different from using std::exception ?
You can't add your own stuff to a live std::exception.
I believe equivalent functionality is available. I believe that boost exception is more intrusive that it has to be. Robert Ramey
Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

AMDG On 06/23/2012 04:19 PM, Robert Ramey wrote:
or if you want to add your own sauce
catch(std::exception &e){ std::exception_ptr e = std::current_exception(); someclass se(e, extra stuff); // home brew or from some library std::throw(se); }
or if you want to catch anyone's stuff
catch(...){ std::exception_ptr e = std::current_exception(); my_unknown_exception me(e); // though its not clear what the upper level could do with this }
this would confine the usage of boost exception to areas where the user can decide whether or not he want's to use it. It looks to me that the standard was conceived to support just this usage.
I disagree. std::exception_ptr was primarily designed to allow exceptions to be passed between threads. The interface doesn't allow you to do much besides rethrowing it unchanged.
It doesn't require anything special at the throw point. The standard facility of using one's own exception class is sufficient.
Doing this means that the caller has to catch someclass or my_unknown_exception instead of boost::archive_exception. It's true that using exception_ptr preserves all the information from the original exception, but it doesn't do it in a very convenient or accessible way. Even worse, if you use this in pre-existing code, you've just introduced a breaking change, because the type of the exception that comes out is different.
If the point of this catch is to translate the type of the exception object, it has to look like:
<snip>
And of course this nonsense has to go around every call to Boost Serialization.
WHY?
lol - well you've got a point here. But I not convinced a huge problem in practice. I would expect most of these would be placed at the much higer levels.
I don't see why that would be the case. The point of using Boost.Exception is to be able to add context information to any exception as it goes by, not to do any real error handling.
How is this different from using std::exception ?
You can't add your own stuff to a live std::exception.
I believe equivalent functionality is available. I believe that boost exception is more intrusive that it has to be.
Boost.Exception helps keep the exception hierarchy clean. a) The type of the exception indicates the actual error that occurred and contains any information specific to the error. b) boost::exception contains various information about the context of the exception. Your latest solution mixes (a) and (b) in a way that makes (a) difficult to get at. In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
On 06/23/2012 04:19 PM, Robert Ramey wrote:
or if you want to add your own sauce
catch(std::exception &e){ std::exception_ptr e = std::current_exception(); someclass se(e, extra stuff); // home brew or from some library std::throw(se); }
or if you want to catch anyone's stuff
catch(...){ std::exception_ptr e = std::current_exception(); my_unknown_exception me(e); // though its not clear what the upper level could do with this }
this would confine the usage of boost exception to areas where the user can decide whether or not he want's to use it. It looks to me that the standard was conceived to support just this usage.
I disagree. std::exception_ptr was primarily designed to allow exceptions to be passed between threads. The interface doesn't allow you to do much besides rethrowing it unchanged. Doing this means that the caller has to catch someclass or my_unknown_exception instead of boost::archive_exception. It's true that using exception_ptr preserves all the information from the original exception, but it doesn't do it in a very convenient or accessible way.
hmmm - how do you believe that those who wrote the standard envisioned that this would be caught an handled?
Even worse, if you use this in pre-existing code, you've just introduced a breaking change, because the type of the exception that comes out is different.
I'm not seeing this. If I throw a member of the class archive_exception, trap it in the above and rethrow it. Cannot I can catch it the same way I did here?
I don't see why that would be the case. The point of using Boost.Exception is to be able to add context information to any exception as it goes by, not to do any real error handling.
I did this with "someclass" above. presumable the mechanics of "someclass" would be some part of boost exception. Then sometime higher one would catch someclass. since someclass copies the pointer there would be no slicing. This would be pretty much the same as boost exception as I understand it but not require any special code at the throw site.
How is this different from using std::exception ? You can't add your own stuff to a live std::exception. I believe equivalent functionality is available. I believe that boost exception is more intrusive that it has to be.
Boost.Exception helps keep the exception hierarchy clean.
a) The type of the exception indicates the actual error that occurred and contains any information specific to the error.
b) boost::exception contains various information about the context of the exception.
Your latest solution mixes (a) and (b) in a way that makes (a) difficult to get at.
The only substantive difference in functionality between the above and boost exception is that boost exceptiion requires creation of a wrapper at the throw site. I believe that boost exception functionality could be implemented without requiring this. This would be a far better and more robust solution and be much more useful when incorporating exisiting applications. Robert Ramey

AMDG On 06/23/2012 10:25 PM, Robert Ramey wrote:
Steven Watanabe wrote:
I disagree. std::exception_ptr was primarily designed to allow exceptions to be passed between threads. The interface doesn't allow you to do much besides rethrowing it unchanged. Doing this means that the caller has to catch someclass or my_unknown_exception instead of boost::archive_exception. It's true that using exception_ptr preserves all the information from the original exception, but it doesn't do it in a very convenient or accessible way.
hmmm - how do you believe that those who wrote the standard envisioned that this would be caught an handled?
I don't understand. I'm saying that what you're trying to do is beyond the scope of what exception_ptr was designed for. If it could be used like this is would be great, but AFAICT, it doesn't seem to work very well.
Even worse, if you use this in pre-existing code, you've just introduced a breaking change, because the type of the exception that comes out is different.
I'm not seeing this. If I throw a member of the class archive_exception, trap it in the above and rethrow it. Cannot I can catch it the same way I did here?
You can't, because the exception that was rethrown is myclass, not archive_exception.
I don't see why that would be the case. The point of using Boost.Exception is to be able to add context information to any exception as it goes by, not to do any real error handling.
I did this with "someclass" above. presumable the mechanics of "someclass" would be some part of boost exception. Then sometime higher one would catch someclass. since someclass copies the pointer there would be no slicing. This would be pretty much the same as boost exception as I understand it but not require any special code at the throw site.
Okay. Let's make this more concrete: Consider code that looks like this: void f(std::string filename) { // Use Boost.Serialization } void g() { try { f(); } catch(boost::archive_exception& e) { /*...*/ } catch(another_exception& e) { /*...*/ } } (This is very simplified. g doesn't have to call f directly, and f doesn't have to use Boost.Serialization directly.) Now, suppose that we want to add the filename to the exception in f. Using Boost.Exception: void f(std::string filename) { try { // Use Boost.Serialization } catch(boost::exception& e) { e << archive_filename(filename); throw; } } Nothing else needs to change. Using your approach: void f(std::string filename) { try { // Use Boost.Serialization } catch(std::exception& e) { throw boost::exception(std::current_exception()) << archive_filename(filename); } } Now, g also has to change: void g() { try { f(); } catch(boost::exception& e) { bool caught = true; try { std::rethrow_exception(e.get_base_exception()); } catch(boost::archive_exception& ae) { /*...*/ } catch(another_exception& ae) { /*...*/ } catch(...) { caught = false; } if (!caught) throw; } } The code has the same effect, but this version of g is a lot harder to understand.
The only substantive difference in functionality between the above and boost exception is that boost exceptiion requires creation of a wrapper at the throw site. I believe that boost exception functionality could be implemented without requiring this. This would be a far better and more robust solution and be much more useful when incorporating exisiting applications.
So, we've added one more element to the list of possible problems. Pick your poison: a) The exception gets sliced b) All possible exception types are enumerated when we add any information to the exception c) User code that handles the exception has to change and becomes really ugly Do you have any more solutions to try? In Christ, Steven Watanabe

On Sat, Jun 23, 2012 at 4:19 PM, Robert Ramey <ramey@rrsd.com> wrote:
Emil Dotchevski wrote:
On Sat, Jun 23, 2012 at 12:11 PM, Robert Ramey <ramey@rrsd.com> wrote:
For example, if Boost Serialization calls boost::throw_exception, an application that serializes data that comes from a web site could store the web address, the user name, port number, or whatever else the application needs to handle the exception.
the serialization libary will likely not have this information. Geneally the serilalizaiton library uses some sort of stream i/o object. Many times errors are detected in the stream. At this point, the none of the library knows what the file name is so it can't be added in until some way higher level.
That is exactly the problem Boost Exception solves. It allows the user to augment library exceptions with application-specific information, after they've been thrown, at a point where the information is naturally available. I believe equivalent functionality is available. I believe that boost
exception is more intrusive that it has to be.
Here is a typical use of boost::exception (obviously at this time this won't work for exceptions emitted by Boost Serialization): catch(boost::exception & e) { e << ip_address(ip) << user_account(u); throw; } If you can think of a way to provide this functionality less intrusively, I'm all ears. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Emil Dotchevski wrote:
On Sat, Jun 23, 2012 at 4:19 PM, Robert Ramey <ramey@rrsd.com> wrote: If you can think of a way to provide this functionality less intrusively, I'm all ears.
I've attached as 100 line test program which I believe demonstrates how functionality like boost::exception can be implemented. a) It won't build with my VS 2008 system. It seems that this version doesn't implement exception_ptr and it's related functions. b) I compiled and linked with gcc 4.5.3 on my CYGWIN system. Here is the resulting output $ ./test_misc caught other exception caught exception_wrapper_base caught my_exception 999 This is the output that I expect. c) The function of the program is as follows 1) The program invokes a chain of calls - the lowest one throws an arbitrary exception - my_exception 2) All exceptions are caught at the next highest level with catch(...) 3) At which an exception_wrapper object is created which contains the original exception along with any data to be attached to the exception. exception_wrapper would more or less correspond to boost::exception. 4) This newly created object is thrown. 5) At the top level, any/all exception_wrapper objects not yet caught are caught and their attached data extracted along with the original exception. d) Note the following: 1) there is no requirement that any special wrapper be applied at the exception site. 2) It works for ALL exception types. There is no requirement that they be derived from some specific base class. 3) It doesn't require RTTI. e) I believe this captures the essential functionality of boost::exception while being totally non-intrusive. Having said that, I didn't look at whole documentation and non of the code of boost::exception so I could easily be missing something. f) I'm aware that the interface presented here is not the most elegant. The purpose here is to demonstrate that boost::exception can be made non-intrusive and to do so in the simplest way. g) I did spend some time looking at boost::exception and the C++ standard documentation on the subjects. Also I spent some time experimenting - this was my second try. As has been pointed out on this list, I'm not very knowledgable in this area, so feel free to point out what I'm missing here. h) This excercise has given me a better understand of the work you've done and the effort you've invested. Of course there's a lot more to it than meets the eye. So please accept my appologies for having given such a hard time. Just in case the attachement gets separated from this email, I'm including the program source below. Robert Ramey // library code #include <exception> // MS compatible compiler 2008 doesn't implement these #if defined(_MSC_VER) namespace std { struct exception_ptr {}; void rethrow_exception(exception_ptr p); exception_ptr current_exception(); } #else // gcc #include <exception_ptr.h> #endif // see 18.8.5 Exception propagation #include <typeinfo> #include <iostream> class exception_wrapper_base : public std::exception { public: const std::exception_ptr m_e; exception_wrapper_base(const std::exception_ptr & e) : m_e(e) { } }; template<class T> class exception_wrapper : public exception_wrapper_base { public: T m_t; exception_wrapper(const std::exception_ptr & e, const T & t) : exception_wrapper_base(e), m_t(t) { } }; template<class T> exception_wrapper<T> make_exception_wrapper(std::exception_ptr e, T t){ return exception_wrapper<T>(e, t); } // example // inside of some other library class my_exception : public std::exception { }; void test_function1(){ throw my_exception(); } // inside a user application // our one special sauce to all the exceptions and // then pass them on. void test_function(){ try { test_function1(); } catch(exception_wrapper_base &ewb){ // if it's already wrapped // ... add sauce // just pass it on throw ewb; } catch(...){ std::cout << "caught other exception" << std::endl; // if it's any other exception // copy the exception pointer std::exception_ptr eptr; try { std::rethrow_exception(std::current_exception()); } catch(...) { eptr = std::current_exception(); } int t = 999; // and create a new exception_wrapper type throw make_exception_wrapper(eptr, t); } } int main(){ try { test_function(); } // to catch some of the exceptions which have been wrapped. catch(exception_wrapper_base & e){ std::cout << "caught exception_wrapper_base" << std::endl; try { std::rethrow_exception(e.m_e); } catch(my_exception & me){ std::cout << "caught my_exception" << std::endl; // e has the added on information // which me has the original information const exception_wrapper<int> & ew = static_cast< exception_wrapper<int> &>(e); std::cout << ew.m_t << std::endl; } catch(...){ // just skip any all other exceptions not specifically handled. } } }

On Sun, Jun 24, 2012 at 11:33 PM, Robert Ramey <ramey@rrsd.com> wrote:
Emil Dotchevski wrote:
On Sat, Jun 23, 2012 at 4:19 PM, Robert Ramey <ramey@rrsd.com> wrote: If you can think of a way to provide this functionality less intrusively, I'm all ears.
I've attached as 100 line test program which I believe demonstrates how functionality like boost::exception can be implemented.
<snipped code> First, as you point out, your code can't be deployed even if it was correct, because many compilers don't yet implement std::exception_ptr. Secondly, your program erases the type of the exception object. In C++, the type of the exception and not its value corresponds to its semantics. That's why the language lets you catch an exception and rethrow it without erasing its type, by using throw without arguments. The program below demonstrates the functionality to be replicated if you're willing to give it another try. Note that app_function stores app-specific info in the exception object without knowing or altering its type. //Library code: #include <boost/throw_exception.hpp> struct lib_exception: public std::exception { }; void lib_function() { boost::throw_exception(lib_exception()); } //Application code: #include <boost/exception/info.hpp> #include <boost/exception/get_error_info.hpp> typedef boost::error_info<struct app_info_,int> app_info; void app_function() { try { lib_function(); } catch( boost::exception & e ) { e << app_info(42); throw; } } int main() { try { app_function(); } catch( lib_exception & e ) { std::cout << "Caught a lib_exception with app_info=" << *boost::get_error_info<app_info>(e); } } Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Emil Dotchevski wrote:
On Sun, Jun 24, 2012 at 11:33 PM, Robert Ramey <ramey@rrsd.com> wrote: <snipped code>
First, as you point out, your code can't be deployed even if it was correct, because many compilers don't yet implement std::exception_ptr.
There a couple of possible answers here, but the simplest would be just to say that you'd need to implement the standard functions for this compiler. I cursory look at the microsoft documentation suggests that this would be possible. and not all that difficult.
Secondly, your program erases the type of the exception object. In C++, the type of the exception and not its value corresponds to its semantics.
hmmm looks to me that my program is not losing the type. The highest level catch does catch the original type and just to be sure I used typeid to print the type restored at this level. So the program output is $ ./test_misc caught other exception # display original exception type caught exception_wrapper_base caught my_exception # display exception type at highest level 999 # display attached information. Robert Ramey

Robert Ramey wrote:
hmmm looks to me that my program is not losing the type.
Looks like you've rediscovered std::nested_exception? http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2559.htm This works but it supports a different (Java-like) style of exception handling. This same mindset has led to exception specifications - libraries have to only throw whatever is enumerated in their interface, so they are forced to wrap. With boost.exception, the high level catch still receives the original exception type, without needing to unwrap. It can then probe for further information if it likes, or it could ignore it (doesn't necessarily have to be rewritten as additional layers are inserted.) In other words: With wrapping: throw X catch X, throw Y(X) catch Y A new layer is inserted: throw X catch X, throw Y(X) catch Y, throw Z(Y) catch Z // this had to change With boost.exception throw X catch X, add info, rethrow X catch X Note how the final catch X doesn't need to change if another layer is inserted: throw X catch X, add info, rethrow X catch X, add info, rethrow X catch X

Peter Dimov wrote:
Robert Ramey wrote:
hmmm looks to me that my program is not losing the type.
Looks like you've rediscovered std::nested_exception?
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2559.htm
I did see this but didn't understand it. A common problem with C++ libraries is that they're not well explained.
This works but it supports a different (Java-like) style of exception handling. This same mindset has led to exception specifications - libraries have to only throw whatever is enumerated in their interface, so they are forced to wrap. With boost.exception, the high level catch still receives the original exception type, without needing to unwrap. It can then probe for further information if it likes, or it could ignore it (doesn't necessarily have to be rewritten as additional layers are inserted.)
In other words:
With wrapping:
throw X catch X, throw Y(X) catch Y
A new layer is inserted:
throw X catch X, throw Y(X) catch Y, throw Z(Y) catch Z // this had to change
With boost.exception
throw X catch X, add info, rethrow X catch X
I didn't really think about this, but now you mention it I'm convinced that my interface is far superior. I guess this last catch X uses the multiple inheritace of the boost exception object to permit catch X rather than catch boost::exception which syntatically looks clean. But now you've got an interface - catch X which actually is an X++. To me this is very bad practice. It hides too much. It's not at all obvious whether or not one can extract extra data from this - it depends on how the exception is thrown. I would like to know that if I catch a "my_exception" that's what I'm getting no more no less. My interface makes this much clearer. That is, I think
catch Z // this had to change is much better than catch X // where X is really an X + some other data
One more thing to argue about. Looking at my make_exception_wrapper, it might be possible to use the boost exception technique so on could replicate the catch X behavior if he wanted to. Really I didn't look at that aspect.
Note how the final catch X doesn't need to change if another layer is inserted:
throw X catch X, add info, rethrow X catch X, add info, rethrow X catch X
maybe - but this is a small benefit in exchange for the price of having to a) wrap all the throws at the throw site b) not being able add data to any throw exception. Really, it's just not practical that for a library to be useful one has to require all the users to change their exception throwing code. How does boost exception deal with third party libraries for which we don't even have the source code? FWIW - The assertion was that it was not possible to implement functionality of boost exception without wrapping exceptions at the throw site. I believe I have shown a counter example to this assertion. This was my goal and I feel I've fullfilled it. To ask more of me here would be moving the goalposts. I'm sure if I had nothing else to do, This could be crafted into a slicker interface. But this is beyond the scope of the original question. Actually I'm sure this technique could be integrated into boost exception - at a cost of changing some of the boost exception interface, which would yield a non-intrusive, more robust, more portable library. Robert Ramey

On Mon, Jun 25, 2012 at 11:50 AM, Robert Ramey <ramey@rrsd.com> wrote:
permit catch X rather than catch boost::exception which syntatically looks clean.
This is not syntactic sugar. I am surprised that I have to defend the position that if a library's documentation says "the library throws X" then the application can catch(X &).
But now you've got an interface - catch X which actually is an X++. To me this is very bad practice. It hides too much. It's not at all obvious whether or not one can extract extra data from this - it depends on how the exception is thrown.
Look at the postcondition of op<< ( http://www.boost.org/doc/libs/release/libs/exception/doc/exception_operator_...). As a matter of fact, users can rely on library exceptions to always arrive with various application-specific data at the catch site. I would like to know that if I catch a "my_exception" that's what
I'm getting no more no less. My interface makes this much clearer.
Like Peter said, others have argued your position in the past and the result is that C++ has exception specifications. I'm warning you, there are dragons down that route, you don't want to go there.
That is, I think
catch Z // this had to change is much better than catch X // where X is really an X + some other data
One more thing to argue about.
Looking at my make_exception_wrapper, it might be possible to use the boost exception technique so on could replicate the catch X behavior if he wanted to.
How?
Really, it's just not practical that for a library to be useful one has to require all the users to change their exception throwing code. How does boost exception deal with third party libraries for which we don't even have the source code?
There are limits to what can be done. Can Boost Serialization serialize any object from a third party library for which we don't even have the source code -- or even if we have it?
FWIW - The assertion was that it was not possible to implement functionality of boost exception without wrapping exceptions at the throw site. I believe I have shown a counter example to this assertion.
You've shown that something different from what Boost Exception can be implemented with std::exception_ptr, which very few compilers support anyway. OTOH, you could use boost::exception_ptr to implement your wrapping code on pretty much any compiler, though -- bummer -- that won't work for exceptions emitted by Boost Serialization. :) Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On 06/25/2012 02:50 PM, Robert Ramey wrote:
With boost.exception
throw X catch X, add info, rethrow X catch X I didn't really think about this, but now you mention it I'm convinced that my interface is far superior.
For an App using an API this scenario is the most pleasant. It allows the two ways App developers need throw X catch X or the one above. I'm unfocused on how an exception/class's members/properties fill in but at the final catch want it to be complete with exception message and the what-caused-it-from-where-info available. (With only one exception framework to learn and maintain). If another library/API uses boost the App needs the API's to do the filling in where the info is available and the App's code very tight, readable and maintainable. And threads are becoming more involved as hardware starts to go to more and more cpu's. Even areas that weren't often paralleled before will be. (Just can't sit there with 7 or more idle processors nowadays)
I guess this last catch X uses the multiple inheritace of the boost exception object to permit catch X rather than catch boost::exception which syntatically looks clean. But now you've got an interface - catch X which actually is an X++.
It is actually throw X-- catch X--, add info, rethrow X catch X My preference is to not know anything about X-- or learn about and write for Y, Z or W, U and V layers, adders to or representatives of X--. Just want X.

On Mon, Jun 25, 2012 at 2:22 PM, Roger Martin <roger@quantumbioinc.com>wrote:
I'm unfocused on how an exception/class's members/properties fill in but at the final catch want it to be complete with exception message and the what-caused-it-from-where-info available. (With only one exception framework to learn and maintain).
A side note, it usually isn't a good idea to store user messages in exception objects. Typically, messages need to be localized, and that is outside of the scope of most of the application code, nevermind library level code. The user message is best formatted in the usually few places where the program actually handles exceptions. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

A side note, it usually isn't a good idea to store user messages in exception objects. Typically, messages need to be localized, and that is outside of the scope of most of the application code, nevermind library level code. In order to localize them you need to keep track of all possible error messages in a .po file, and since new error codes can appear in new
On Mon, 25 Jun 2012 15:58:14 -0700 Emil Dotchevski <emildotchevski@gmail.com> wrote: library version this can be only dependably handled at library level. Otherwise we'll either have to lose the original message or display it in English. Translating messages from libraries in apps just won't scale.

I would like to know that if I catch a "my_exception" that's what I'm getting no more no less. My interface makes this much clearer.
The design of the language is inherently no less, but possibly more. catch (X & x) means X or derived from X. Ie X or more, no less. Tony <this is not an endorsement of any other opinions of the overall discussion. Just wanted to highlight that point. Also sorry for basically top-posting. Email on tablets still hasn't been perfected> Sent from my portable Analytical Engine ------------------------------ *From:* "Robert Ramey" <ramey@rrsd.com> *To:* "boost@lists.boost.org" <boost@lists.boost.org> *Sent:* 25 June, 2012 2:50 PM *Subject:* Re: [boost] Boost and exceptions Peter Dimov wrote:
Robert Ramey wrote:
hmmm looks to me that my program is not losing the type.
Looks like you've rediscovered std::nested_exception?
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2559.htm
I did see this but didn't understand it. A common problem with C++ libraries is that they're not well explained.
This works but it supports a different (Java-like) style of exception handling. This same mindset has led to exception specifications - libraries have to only throw whatever is enumerated in their interface, so they are forced to wrap. With boost.exception, the high level catch still receives the original exception type, without needing to unwrap. It can then probe for further information if it likes, or it could ignore it (doesn't necessarily have to be rewritten as additional layers are inserted.)
In other words:
With wrapping:
throw X catch X, throw Y(X) catch Y
A new layer is inserted:
throw X catch X, throw Y(X) catch Y, throw Z(Y) catch Z // this had to change
With boost.exception
throw X catch X, add info, rethrow X catch X
I didn't really think about this, but now you mention it I'm convinced that my interface is far superior. I guess this last catch X uses the multiple inheritace of the boost exception object to permit catch X rather than catch boost::exception which syntatically looks clean. But now you've got an interface - catch X which actually is an X++. To me this is very bad practice. It hides too much. It's not at all obvious whether or not one can extract extra data from this - it depends on how the exception is thrown. I would like to know that if I catch a "my_exception" that's what I'm getting no more no less. My interface makes this much clearer. That is, I think
catch Z // this had to change is much better than catch X // where X is really an X + some other data
One more thing to argue about. Looking at my make_exception_wrapper, it might be possible to use the boost exception technique so on could replicate the catch X behavior if he wanted to. Really I didn't look at that aspect.
Note how the final catch X doesn't need to change if another layer is inserted:
throw X catch X, add info, rethrow X catch X, add info, rethrow X catch X
maybe - but this is a small benefit in exchange for the price of having to a) wrap all the throws at the throw site b) not being able add data to any throw exception. Really, it's just not practical that for a library to be useful one has to require all the users to change their exception throwing code. How does boost exception deal with third party libraries for which we don't even have the source code? FWIW - The assertion was that it was not possible to implement functionality of boost exception without wrapping exceptions at the throw site. I believe I have shown a counter example to this assertion. This was my goal and I feel I've fullfilled it. To ask more of me here would be moving the goalposts. I'm sure if I had nothing else to do, This could be crafted into a slicker interface. But this is beyond the scope of the original question. Actually I'm sure this technique could be integrated into boost exception - at a cost of changing some of the boost exception interface, which would yield a non-intrusive, more robust, more portable library. Robert Ramey _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

AMDG On 06/25/2012 09:37 AM, Robert Ramey wrote:
Emil Dotchevski wrote:
On Sun, Jun 24, 2012 at 11:33 PM, Robert Ramey <ramey@rrsd.com> wrote: <snipped code>
First, as you point out, your code can't be deployed even if it was correct, because many compilers don't yet implement std::exception_ptr.
There a couple of possible answers here, but the simplest would be just to say that you'd need to implement the standard functions for this compiler. I cursory look at the microsoft documentation suggests that this would be possible. and not all that difficult.
Secondly, your program erases the type of the exception object. In C++, the type of the exception and not its value corresponds to its semantics.
hmmm looks to me that my program is not losing the type.
That's not what Emil said. "erases the type" means that it hides everything behind a single static type and forces you to dynamic cast to find the real type. I really don't want to read or write code that looks like this, and I don't think that the problem can be solved without adding something to the original throw site. The problems become even worse when you have more than one independent implementation of this kind of handling, which don't know about each other: void handle_my_exception(my_exception&); void handle_exception_wrapper1(exception_wrapper_base1& e) { try { std::rethrow_exception(e.me); } catch(my_exception& me) { handle_my_exception(me); } catch(exception_wrapper_base2& e2) { handle_exception_wrapper2(e2); } catch(...) { handle_unknown_exception(); } } void handle_exception_wrapper2(exception_wrapper_base2& e) { try { std::rethrow_exception(e.me); } catch(my_exception& me) { handle_my_exception(me); } catch(exception_wrapper_base1& e1) { handle_exception_wrapper1(e1); } catch(...) { handle_unknown_exception(); } } try { // Lots of stuff } catch(my_exception& e) { handle_my_exception(e); } catch(exception_wrapper_base1& e) { handle_exception_wrapper1(e); } catch(exception_wrapper_base2& e) { handle_exception_wrapper2(e); } I don't even want to think about what you need to do if you want to let anything that isn't my_exception go by unchanged. I think that you've gotten so fixated on avoiding instrumenting the original throw site, that it's blinding to the readability issues with your solutions.
The highest level catch does catch the original type and just to be sure I used typeid to print the type restored at this level. So the program output is
$ ./test_misc caught other exception # display original exception type caught exception_wrapper_base caught my_exception # display exception type at highest level 999 # display attached information.
In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
I think that you've gotten so fixated on avoiding instrumenting the original throw site, that it's blinding to the readability issues with your solutions.
Well, I AM fixated on the requirement to instrument the original throw site. I wouldn't have cared except for the way it was attempted to enforce this requirement. But now that I've been made to care about it, I'll state that this is the fundamental problem with the library. To try to impose such a requirement on the libraries on application might use is not realistic. Boost is not the whole universe of libraries. My example was to demonstrate that was asserted to not be possible is in fact possible. I'm sure if I had nothing else to do I could make a more user friendly interface. But it wasn't my task to do so. I wanted to make the machinery visible for this discussion. Robert Ramey

On Mon, Jun 25, 2012 at 7:28 PM, Robert Ramey <ramey@rrsd.com> wrote:
Steven Watanabe wrote:
AMDG
I think that you've gotten so fixated on avoiding instrumenting the original throw site, that it's blinding to the readability issues with your solutions.
Well, I AM fixated on the requirement to instrument the original throw site. I wouldn't have cared except for the way it was attempted to enforce this requirement. But now that I've been made to care about it, I'll state that this is the fundamental problem with the library. To try to impose such a requirement on the libraries on application might use is not realistic.
Currently there is no requirement for Boost libraries to call boost::throw_exception to throw. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Sun, Jun 24, 2012 at 11:33 PM, Robert Ramey <ramey@rrsd.com> wrote:
h) This excercise has given me a better understand of the work you've done and the effort you've invested. Of course there's a lot more to it than meets the eye. So please accept my appologies for having given such a hard time.
Robert, thanks for saying this -- and yes, it is a tricky subject indeed. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On 24.06.2012, at 01:19, Robert Ramey wrote:
Emil Dotchevski wrote:
On Sat, Jun 23, 2012 at 12:11 PM, Robert Ramey <ramey@rrsd.com> wrote:
For example, if Boost Serialization calls boost::throw_exception, an application that serializes data that comes from a web site could store the web address, the user name, port number, or whatever else the application needs to handle the exception.
the serialization libary will likely not have this information. Geneally the serilalizaiton library uses some sort of stream i/o object. Many times errors are detected in the stream. At this point, the none of the library knows what the file name is so it can't be added in until some way higher level. The current archive_exception class holds all the useful information which is available.
And boost::exception allows the surrounding code to add the information that wasn't available to the serialization library. That's the whole point!
your code when you eventually can eventually rethrow
catch (std::exception e){ BOOST_EXCEPTION_THROW_EXCEPTION(e) }
Second, even if you catch std::exception & obj, throwing obj will slice, erasing the dynamic type of the original exception.
It's hard to see the slicing through the macro
The slicing assumption is there by default because C++ cannot do any better. The only way to avoid slicing would be to enumerate all possible dynamic types that could possibly be thrown here. Given that user-defined types can throw user-defined exceptions while deserializing, this is somewhere between "extremely difficult and fragile to far-off code changes" and "impossible".
isn't the standard way of handling this better?
catch(std::exception & e){ std::exception_ptr e = std::current_exception(); std::rethrow_exception(e); }
This doesn't do anything. What are you trying to achieve?
or if you want to add your own sauce
catch(std::exception &e){ std::exception_ptr e = std::current_exception(); someclass se(e, extra stuff); // home brew or from some library std::throw(se); }
or if you want to catch anyone's stuff
catch(...){ std::exception_ptr e = std::current_exception(); my_unknown_exception me(e); // though its not clear what the upper level could do with this }
this would confine the usage of boost exception to areas where the user can decide whether or not he want's to use it. It looks to me that the standard was conceived to support just this usage. It doesn't require anything special at the throw point. The standard facility of using one's own exception class is sufficient.
As Steven pointed out, it isn't. You lose type information. Using your own exception class that contains an exception_ptr (or using std::throw_with_nested) is fine if you want to do true translation of the exception, but not if you want to preserve the original exception (so that catch sites can refer to the original type). It's the way the C++ exception system works: the only point where full type information is statically available is at the throw site. This is why Boost.Exception has to hook that point, and not anything else.
lol - well you've got a point here. But I not convinced a huge problem in practice. I would expect most of these would be placed at the much higer levels.
Not if the point is to enable boost::exception support and thus allow additional information to be attached. Also, enumerating types is, as I mentioned, extremely fragile. Do you absolutely promise not to ever throw something that derives from archive::exception instead of that class itself? Did you document this promise in your library? Did you document that no library extension functionality must throw anything but plain archive::exception objects or else have a big fat warning in their documentation? If you didn't, then I can't catch your exception and add boost::exception functionality. You have to do it.
How is this different from using std::exception ?
You can't add your own stuff to a live std::exception.
I believe equivalent functionality is available.
You're wrong about this. Sebastian

On Fri, Jun 22, 2012 at 5:23 AM, Stewart, Robert <Robert.Stewart@sig.com>wrote:
Robert Ramey wrote:
Dave Abrahams wrote:
I mean, if there is a problem with boost::throw_exception or any other part of Boost Exception, I'd like to know about it.
It seems clear to me from his posts that Robert wants to talk about the process and has forgotten any specifics about actual problems.
The problem was the gratuitious inclusion of a new dependency.
Emil has described repeatedly why the change was not gratuitous. That you fail to recognize the value in the change does not make it gratuitous.
I looked at a recent boost/throw_exception.hpp. It includes boost/exception/detail/attribute_noreturn.hpp. That creates a dependency inversion that is unfortunate.
Obviously this is separated in a header with the prospect of becoming an official Boost header. OTOH, this functionality didn't exist, which presumably means that nobody else needs it. (I do not see the "dependency inversion" as a problem.) The header also conditionally includes the non-trivial
boost/exception/exception.hpp, another dependency inversion, which defines many types and functions, and includes some inline function definitions
Sure, that's what headers do. :) Pretty much all of this header is implementation details. The bit that concerns the user is that it's a couple hundred lines of self-contained code with absolutely no external dependencies.
If BOOST_EXCEPTION_DISABLE is not defined, then boost::throw_exception() tacks on Boost.Exception features to the exception being thrown.
This is a non-trivial set of changes to make to the top-level header.
It's non-trivial in that it enables the library to function. It's trivial in terms of cost and backwards compatibility. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On 06/22/2012 02:23 PM, Stewart, Robert wrote:
In hindsight, I agree with Robert's assertion that there should have been a replacement function, boost::exception::throw_exception() or similar, to introduce the new functionality. Whether the existing function needed to be deprecated is a separate issue. The result is that libraries could knowingly choose the new version, and a dependency on Boost.Exception, or, if warranted, stick with the old.
That would be a terrible idea. The whole point of the system is that there is a single place where you enable Boost.Exception support for all libraries. If some libraries were allowed to stick to non-Boost.Exception-enabled boost::throw_exception, then you couldn't transfer those exceptions between threads.

On Sat, Jun 23, 2012 at 2:30 AM, Mathias Gaunard < mathias.gaunard@ens-lyon.org> wrote:
On 06/22/2012 02:23 PM, Stewart, Robert wrote:
In hindsight, I agree with Robert's assertion that there should have been
a replacement function, boost::exception::throw_**exception() or similar, to introduce the new functionality. Whether the existing function needed to be deprecated is a separate issue. The result is that libraries could knowingly choose the new version, and a dependency on Boost.Exception, or, if warranted, stick with the old.
That would be a terrible idea.
The whole point of the system is that there is a single place where you enable Boost.Exception support for all libraries.
If some libraries were allowed to stick to non-Boost.Exception-enabled boost::throw_exception, then you couldn't transfer those exceptions between threads.
Well, clearly, some libraries have been allowed their own throw_exception implementation for some time, notably Boost.Serialization and Boost.FileSystem.
From what I can find in the list archives [1], Boost.FileSystem also had a similar issue with the requirement that thrown exceptions inherit from std::exception. However, I'm not sure if [1] prompted the FileSystem-local hook or if it was resolved in some other way.
- Jeff [1] http://lists.boost.org/Archives/boost/2008/05/138016.php

On 06/23/2012 12:25 PM, Jeffrey Lee Hellrung, Jr. wrote:
From what I can find in the list archives [1], Boost.FileSystem also had a similar issue with the requirement that thrown exceptions inherit from std::exception. However, I'm not sure if [1] prompted the FileSystem-local hook or if it was resolved in some other way.
All exceptions should inherit from std::exception. There is no need to involve the boost::exception type in your code to use throw_exception.

From what I can find in the list archives [1], Boost.FileSystem also had a similar issue with the requirement that thrown exceptions inherit from std::exception. However, I'm not sure if [1] prompted the FileSystem-local hook or if it was resolved in some other way.
All exceptions should inherit from std::exception. There is no need to involve the boost::exception type in your code to use throw_exception.
This works both ways - you can and should inherit from std::exception whether you use BOOST_THROW_EXCEPTION or not, it's just that in the latter case, they will also inherit from boost::exception (via multiple inheritance if I understand the machinery correctly). John.

On Sat, Jun 23, 2012 at 7:22 AM, John Maddock <boost.regex@virgin.net>wrote:
From what I can find in the list archives [1], Boost.FileSystem also had a
similar issue with the requirement that thrown exceptions inherit from std::exception. However, I'm not sure if [1] prompted the FileSystem-local hook or if it was resolved in some other way.
All exceptions should inherit from std::exception. There is no need to involve the boost::exception type in your code to use throw_exception.
This works both ways - you can and should inherit from std::exception whether you use BOOST_THROW_EXCEPTION or not, it's just that in the latter case, they will also inherit from boost::exception (via multiple inheritance if I understand the machinery correctly).
Yes, any exception emitted by boost::throw_exception can be intercepted as std::exception (you get a compile error if you pass a type that doesn't derive from std::exception), or as boost::exception (it's inserted as a base type if the passed type doesn't already derive from it). Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Sat, Jun 23, 2012 at 5:57 AM, Mathias Gaunard < mathias.gaunard@ens-lyon.org> wrote:
On 06/23/2012 12:25 PM, Jeffrey Lee Hellrung, Jr. wrote:
From what I can find in the list archives [1], Boost.FileSystem also had a
similar issue with the requirement that thrown exceptions inherit from std::exception. However, I'm not sure if [1] prompted the FileSystem-local hook or if it was resolved in some other way.
All exceptions should inherit from std::exception. There is no need to involve the boost::exception type in your code to use throw_exception.
There were a few examples of libraries emitting exceptions that did not derive from std::exception in violation of a boost::throw_exception requirement. This requirement was not enforced prior to Boost version 1.36. With the introduction of Boost Exception, we got compile errors in the offending libraries. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Emil Dotchevski wrote:
There were a few examples of libraries emitting exceptions that did not derive from std::exception in violation of a boost::throw_exception requirement.
The original boost::throw_exception or the current one?
This requirement was not enforced prior to Boost version 1.36. With the introduction of Boost Exception, we got compile errors in the offending libraries.
Does this mean that if some user/library uses exceptions which don't derive from std::exception he can't use the boost exception library? Does Boost exception actually depend on the argument to boost::throw_exception being drived from std::exception? Robert Ramey
Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

AMDG On 06/23/2012 03:29 PM, Robert Ramey wrote:
Emil Dotchevski wrote:
There were a few examples of libraries emitting exceptions that did not derive from std::exception in violation of a boost::throw_exception requirement.
The original boost::throw_exception or the current one?
The requirement was always present implicitly. When exceptions are disabled, the signature is void throw_exception(const std::exception&); which is obviously not going going to work if the exception doesn't derive from std::exception. In Christ, Steven Watanabe

On Sat, Jun 23, 2012 at 3:29 PM, Robert Ramey <ramey@rrsd.com> wrote:
Emil Dotchevski wrote:
There were a few examples of libraries emitting exceptions that did not derive from std::exception in violation of a boost::throw_exception requirement.
The original boost::throw_exception or the current one?
The original one, which unfortunately did not enforce the requirement. The current one does.
This requirement was not enforced prior to Boost version 1.36. With
the introduction of Boost Exception, we got compile errors in the offending libraries.
Does this mean that if some user/library uses exceptions which don't derive from std::exception he can't use the boost exception library?
It means that if some Boost library ever passed to boost::throw_exception an object of type that doesn't derive from std::exception, it'll lead to compile errors under BOOST_NO_EXCEPTIONS. I'll let you figure out why. Currently, you'll get a compile error in any configuration. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Mathias Gaunard wrote:
On 06/22/2012 02:23 PM, Stewart, Robert wrote:
In hindsight, I agree with Robert's assertion that there should have been a replacement function, boost::exception::throw_exception() or similar, to introduce the new functionality. Whether the existing function needed to be deprecated is a separate issue. The result is that libraries could knowingly choose the new version, and a dependency on Boost.Exception, or, if warranted, stick with the old.
That would be a terrible idea.
The whole point of the system is that there is a single place where you enable Boost.Exception support for all libraries.
The original point of boost::throw_exception() was to provide a fallback when exception support is not available. That it now enables Boost.Exception support is the problem for some.
If some libraries were allowed to stick to non- Boost.Exception-enabled boost::throw_exception, then you couldn't transfer those exceptions between threads.
You could in C++11, but that's another matter. There is no Boost policy that requires Boost.Exception support. If you think there should be, then lobby for it. Until then, library authors and maintainers can choose to not support Boost.Exception, yet their libraries should be supported when exceptions are not. _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com ________________________________ IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On 25 June 2012 17:43, Stewart, Robert <Robert.Stewart@sig.com> wrote:
Mathias Gaunard wrote:
The whole point of the system is that there is a single place where you enable Boost.Exception support for all libraries.
The original point of boost::throw_exception() was to provide a fallback when exception support is not available. That it now enables Boost.Exception support is the problem for some.
Everything's always a problem for someone. Maybe it should have been opt-in rather than opt-out (for the user), but I don't think that would be an appropriate change now.
If some libraries were allowed to stick to non- Boost.Exception-enabled boost::throw_exception, then you couldn't transfer those exceptions between threads.
You could in C++11, but that's another matter.
There is no Boost policy that requires Boost.Exception support. If you think there should be, then lobby for it. Until then, library authors and maintainers can choose to not support Boost.Exception
As with writing warning free code, it isn't a policy but it is desirable.
yet their libraries should be supported when exceptions are not.
Supported by whom?

Daniel James wrote:
On 25 June 2012 17:43, Stewart, Robert <Robert.Stewart@sig.com> wrote:
Mathias Gaunard wrote:
The whole point of the system is that there is a single place where you enable Boost.Exception support for all libraries.
The original point of boost::throw_exception() was to provide a fallback when exception support is not available. That it now enables Boost.Exception support is the problem for some.
Everything's always a problem for someone. Maybe it should have been opt-in rather than opt-out (for the user), but I don't think that would be an appropriate change now.
I'm not suggesting that. Mathias was mischaracterizing the original purpose of the function.
If some libraries were allowed to stick to non- Boost.Exception-enabled boost::throw_exception, then you couldn't transfer those exceptions between threads.
You could in C++11, but that's another matter.
There is no Boost policy that requires Boost.Exception support. If you think there should be, then lobby for it. Until then, library authors and maintainers can choose to not support Boost.Exception
As with writing warning free code, it isn't a policy but it is desirable.
Perhaps you're right, but if that isn't documented somewhere, or caught by reviewers for new libraries, then support will be spotty.
yet their libraries should be supported when exceptions are not.
Supported by whom?
I meant that there should be a standard Boost mechanism for such libraries to have a no-exceptions fallback without Boost.Exception support. (If the community decides that Boost.Exception support is required, then this wouldn't be needed.) _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com ________________________________ IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On 25 June 2012 18:29, Stewart, Robert <Robert.Stewart@sig.com> wrote:
Daniel James wrote:
On 25 June 2012 17:43, Stewart, Robert <Robert.Stewart@sig.com> wrote:
Mathias Gaunard wrote:
The whole point of the system is that there is a single place where you enable Boost.Exception support for all libraries.
The original point of boost::throw_exception() was to provide a fallback when exception support is not available. That it now enables Boost.Exception support is the problem for some.
Everything's always a problem for someone. Maybe it should have been opt-in rather than opt-out (for the user), but I don't think that would be an appropriate change now.
I'm not suggesting that.
I didn't think you were.
yet their libraries should be supported when exceptions are not.
Supported by whom?
I meant that there should be a standard Boost mechanism for such libraries to have a no-exceptions fallback without Boost.Exception support. (If the community decides that Boost.Exception support is required, then this wouldn't be needed.)
I would hope a developer would be capable of doing that themselves, all they need to do is call 'boost::throw_exception' when BOOST_NO_EXCEPTIONS is defined. They could perhaps ask Emil to supply a header that just declares it. Having two exception mechanisms would be confusing.

On 06/22/2012 02:23 PM, Stewart, Robert wrote:
There is no Boost policy that requires Boost.Exception support. If you think there should be, >then lobby for it.
This thread has pushed me in the direction that this is the way to go. Here are some specific policy change proposals: 1) Mandate that all throws should be through BOOST_THROW_EXCEPTION and enforce through Boost.Inspect. or: 2) Strongly suggest in developer documentation that they should be through BOOST_THROW_EXCEPTION but drop short of mandating. or: 3) Better document and formalize existing practice (that user-visible exceptions should derive from std::exception, and that a developer may use BOOST_THROW_EXCEPTION and boost::throw_exception and may respect BOOST_NO_EXCEPTIONS, but isn't obliged to do so) Pros for 1) and 2): - All libraries naturally support the BOOST_NO_EXCEPTIONS config without further work on their part. - All libraries benefit fully from Boost.Exception functionality. - All libraries benefit from future improvements to Boost.Exception (e.g. possible improvements relating to cross-thread exception handling) Cons for 1) and 2): - Always paying for the cost of #including <boost/throw_exception.hpp> - All libraries are dependent on - and therefore become vulnerable to any future breakages (if any) in - Boost.Exception. Cons for 1) - This would (a little) reduce the autonomy that Boost authors have to implement as they see fit. Historically Boost authors have great individual freedom and imposing restrictions may be unattractive to (volunteer) devs. FWIW, I'm firmly in favour of 1). Re the cons, I don't think the cost of extra includes will be the straw that breaks the camel's back, particularly when users are already likely to be putting Boost in a PCH. Re the second con, I think Boost should collectively be prepared to eat its own dogfood - if Boost.Exception does ever break, users will be affected too and so any breakages in Boost code will act as an early warning system when testing. Re the third con, I think this is a fair point, but all we are really doing is asking "throw e;" to be replaced by "BOOST_THROW_EXCEPTION(e);" so I don't think creativity is being hindered too much in this case. Thanks for listening! Pete

On Mon, Jun 25, 2012 at 2:32 PM, Pete Bartlett <pete@pcbartlett.com> wrote:
On 06/22/2012 02:23 PM, Stewart, Robert wrote:
There is no Boost policy that requires Boost.Exception support. If you think there should be, >then lobby for it.
This thread has pushed me in the direction that this is the way to go. Here are some specific policy change proposals:
1) Mandate that all throws should be through BOOST_THROW_EXCEPTION and enforce through Boost.Inspect. or:
2) Strongly suggest in developer documentation that they should be through
BOOST_THROW_EXCEPTION but drop short of mandating. or: 3) Better document and formalize existing practice (that user-visible exceptions should derive from std::exception, and that a developer may use BOOST_THROW_EXCEPTION and boost::throw_exception and may respect BOOST_NO_EXCEPTIONS, but isn't obliged to do so)
[...] Regarding (1) and (2), I think one should have the option to simply use boost::throw_exception. The additional file/function/line info may not be very useful within a templated implementation detail, and, in any case, such info is likely only useful/usable in a debugging context. - Jeff

On Mon, Jun 25, 2012 at 2:13 PM, Jeffrey Lee Hellrung, Jr. < jeffrey.hellrung@gmail.com> wrote:
On Mon, Jun 25, 2012 at 2:32 PM, Pete Bartlett <pete@pcbartlett.com> wrote:
On 06/22/2012 02:23 PM, Stewart, Robert wrote:
There is no Boost policy that requires Boost.Exception support. If you think there should be, >then lobby for it.
This thread has pushed me in the direction that this is the way to go. Here are some specific policy change proposals:
1) Mandate that all throws should be through BOOST_THROW_EXCEPTION and enforce through Boost.Inspect. or:
2) Strongly suggest in developer documentation that they should be through
BOOST_THROW_EXCEPTION but drop short of mandating. or: 3) Better document and formalize existing practice (that user-visible exceptions should derive from std::exception, and that a developer may use BOOST_THROW_EXCEPTION and boost::throw_exception and may respect BOOST_NO_EXCEPTIONS, but isn't obliged to do so)
[...]
Regarding (1) and (2), I think one should have the option to simply use boost::throw_exception. The additional file/function/line info may not be very useful within a templated implementation detail, and, in any case, such info is likely only useful/usable in a debugging context.
boost::exception stores the BOOST_THROW_EXCEPTION information in a custom, more efficient way than other data. The only overhead is the potential bloat from BOOST_CURRENT_FUNCTION, which now can be controlled (see ticket #6450.) At least in my experience BOOST_THROW_EXCEPTION is very helpful in combination with boost::diagnostic_information. In my development environment, I can double-click the message to go to the location of the throw, which makes it easy to set a break point and run again to see the context in which the unexpected exception happens. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On Mon, Jun 25, 2012 at 4:49 PM, Emil Dotchevski <emildotchevski@gmail.com>wrote:
On Mon, Jun 25, 2012 at 2:13 PM, Jeffrey Lee Hellrung, Jr. < jeffrey.hellrung@gmail.com> wrote:
On Mon, Jun 25, 2012 at 2:32 PM, Pete Bartlett <pete@pcbartlett.com> wrote:
On 06/22/2012 02:23 PM, Stewart, Robert wrote:
There is no Boost policy that requires Boost.Exception support. If you think there should be, >then lobby for it.
This thread has pushed me in the direction that this is the way to go. Here are some specific policy change proposals:
1) Mandate that all throws should be through BOOST_THROW_EXCEPTION and enforce through Boost.Inspect. or:
2) Strongly suggest in developer documentation that they should be through
BOOST_THROW_EXCEPTION but drop short of mandating. or: 3) Better document and formalize existing practice (that user-visible exceptions should derive from std::exception, and that a developer may use BOOST_THROW_EXCEPTION and boost::throw_exception and may respect BOOST_NO_EXCEPTIONS, but isn't obliged to do so)
[...]
Regarding (1) and (2), I think one should have the option to simply use boost::throw_exception. The additional file/function/line info may not be very useful within a templated implementation detail, and, in any case, such info is likely only useful/usable in a debugging context.
boost::exception stores the BOOST_THROW_EXCEPTION information in a custom, more efficient way than other data. The only overhead is the potential bloat from BOOST_CURRENT_FUNCTION, which now can be controlled (see ticket #6450.)
At least in my experience BOOST_THROW_EXCEPTION is very helpful in combination with boost::diagnostic_information. In my development environment, I can double-click the message to go to the location of the throw, which makes it easy to set a break point and run again to see the context in which the unexpected exception happens.
Hmmm...should these details be added to the BOOST_THROW_EXCEPTION documentation? It's not at all clear from the documentation what overhead BOOST_THROW_EXCEPTION brings relative to simply boost::throw_exception. - Jeff

On Mon, Jun 25, 2012 at 4:56 PM, Jeffrey Lee Hellrung, Jr. < jeffrey.hellrung@gmail.com> wrote:
On Mon, Jun 25, 2012 at 4:49 PM, Emil Dotchevski> boost::exception stores the BOOST_THROW_EXCEPTION information in a custom,
more efficient way than other data. The only overhead is the potential bloat from BOOST_CURRENT_FUNCTION, which now can be controlled (see ticket #6450.)
At least in my experience BOOST_THROW_EXCEPTION is very helpful in combination with boost::diagnostic_information. In my development environment, I can double-click the message to go to the location of the throw, which makes it easy to set a break point and run again to see the context in which the unexpected exception happens.
Hmmm...should these details be added to the BOOST_THROW_EXCEPTION documentation? It's not at all clear from the documentation what overhead BOOST_THROW_EXCEPTION brings relative to simply boost::throw_exception.
Yes, good idea. I'll add this info in the documentation. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

I don't think creativity is being hindered too much in this case.
Creativity is lost in being able to find yet a better way to handle errors. Of course, if someone came along with a better idea, we could always change our policies yet again, so the creativity isn't completely lost. But do note that it is in some way discouraging experimentation with error handling. That may be a reasonable trade off, just be aware of it. Tony Sent from my portable Analytical Engine ------------------------------ *From:* "Pete Bartlett" <pete@pcbartlett.com> *To:* "boost@lists.boost.org" <boost@lists.boost.org> *Sent:* 25 June, 2012 5:32 PM *Subject:* [boost] Policy proposal: All user-visible exceptions should be thrown through BOOST_THROW_EXCEPTION [was RE: Boost and exceptions]
On 06/22/2012 02:23 PM, Stewart, Robert wrote:
There is no Boost policy that requires Boost.Exception support. If you think there should be, >then lobby for it.
This thread has pushed me in the direction that this is the way to go. Here are some specific policy change proposals: 1) Mandate that all throws should be through BOOST_THROW_EXCEPTION and enforce through Boost.Inspect. or: 2) Strongly suggest in developer documentation that they should be through BOOST_THROW_EXCEPTION but drop short of mandating. or: 3) Better document and formalize existing practice (that user-visible exceptions should derive from std::exception, and that a developer may use BOOST_THROW_EXCEPTION and boost::throw_exception and may respect BOOST_NO_EXCEPTIONS, but isn't obliged to do so) Pros for 1) and 2): - All libraries naturally support the BOOST_NO_EXCEPTIONS config without further work on their part. - All libraries benefit fully from Boost.Exception functionality. - All libraries benefit from future improvements to Boost.Exception (e.g. possible improvements relating to cross-thread exception handling) Cons for 1) and 2): - Always paying for the cost of #including - All libraries are dependent on - and therefore become vulnerable to any future breakages (if any) in - Boost.Exception. Cons for 1) - This would (a little) reduce the autonomy that Boost authors have to implement as they see fit. Historically Boost authors have great individual freedom and imposing restrictions may be unattractive to (volunteer) devs. FWIW, I'm firmly in favour of 1). Re the cons, I don't think the cost of extra includes will be the straw that breaks the camel's back, particularly when users are already likely to be putting Boost in a PCH. Re the second con, I think Boost should collectively be prepared to eat its own dogfood - if Boost.Exception does ever break, users will be affected too and so any breakages in Boost code will act as an early warning system when testing. Re the third con, I think this is a fair point, but all we are really doing is asking "throw e;" to be replaced by "BOOST_THROW_EXCEPTION(e);" so I don't think creativity is being hindered too much in this case. Thanks for listening! Pete _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

2012/6/26 Pete Bartlett <pete@pcbartlett.com>:
This thread has pushed me in the direction that this is the way to go. Here are some specific policy change proposals: ...
I would also advise to use BOOST_SYMBOL_VISIBLE for all the classes, derived from std::exception. This can be enforced by Boost.Inspection. -- Best regards, Antony Polukhin
participants (20)
-
Agustín K-ballo Bergé
-
Antony Polukhin
-
Daniel James
-
Dave Abrahams
-
Emil Dotchevski
-
Fabio Fracassi
-
Gottlob Frege
-
Jeffrey Lee Hellrung, Jr.
-
John Maddock
-
Kim Barrett
-
Mathias Gaunard
-
Nevin Liber
-
Pete Bartlett
-
Peter Dimov
-
Robert Ramey
-
Roger Martin
-
Sebastian Redl
-
Sergey Popov
-
Steven Watanabe
-
Stewart, Robert