Re: [boost] Exception Visitor

I just don't see the point, except as an academic exercise
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Jeremy Day Sent: Tuesday, July 18, 2006 10:32 AM To: boost@lists.boost.org Subject: Re: [boost] Exception Visitor
I don't think that I can get rid of the catch block entirely, but I can make it so that you always use catch(...). The catcher function redirects the exception handling to the class that you provide.
Jeremy
On 7/18/06, Sohail Somani <s.somani@fincad.com> wrote:
Or how to implement try..catch? _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 7/18/06, Sohail Somani <s.somani@fincad.com> wrote:
I just don't see the point, except as an academic exercise
The point is partly academic, as I am working on learning MPL. However, I think that this technique, or some derivation thereof, can help make code more maintainable, since you can reuse my_exception_handler whenever you want to handle the same exception in the same way, even though you catch it in a different place. With catch blocks the only recourse, so far as I can tell, is to basically copy-and-paste the catch code to each location where you need the exception handling code. Jeremy

On 7/19/06, Jeremy Day <jeremy.day@gmail.com> wrote:
With catch blocks the only recourse, so far as I can tell, is to basically copy-and-paste the catch code to each location where you need the exception handling code.
Not really... Instead of copy pasting, you can put it in a method or class and use that handler where you need the exception handling to be done. There are more creative ways and less brute way of handling exceptions, without having to resort to MPL. Whenever you see that the exception is being handled in *almost* the same context, then perhaps you can design your solution so that you handle that exception in a common location as well. It's more about design than it actually is about just handling the exception per se. While exceptions themselves allow you functionality to have interested areas of code handle the exception, they also serve as control structures for program state flaw in the face of exceptional instances -- thus the term exception handling. -- Dean Michael C. Berris C/C++ Software Architect Orange and Bronze Software Labs http://3w-agility.blogspot.com/ http://cplusplus-soup.blogspot.com/ Mobile: +639287291459 Email: dean [at] orangeandbronze [dot] com

Jeremy Day wrote:
However, I think that this technique, or some derivation thereof, can help make code more maintainable, since you can reuse my_exception_handler whenever you want to handle the same exception in the same way, even though you catch it in a different place.
How is your approach better than: // Untested code #include <stdexcept> // Generic handler function void HandleException() { try { throw; } catch (const std::logic_error &) { // whatever } catch (const std::exception &) { // whatever } } int main() { try { // throwing code } catch (...) { HandleException(); } return 0; } ? Regards, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.

On 7/18/06, Andreas Huber <ahd6974-spamgroupstrap@yahoo.com> wrote:
How is your approach better than:
[snip] Heh. Well, when you put it that way it probably isn't. However, the function object that you pass into catcher could contain application state information. You could also use any functor that you happen to have around that has operator()(std::logic_error&), operator()(std::exception&), or operator()(void). Jeremy

Jeremy Day wrote:
On 7/18/06, Andreas Huber <ahd6974-spamgroupstrap@yahoo.com> wrote:
How is your approach better than:
[snip]
Heh. Well, when you put it that way it probably isn't. However, the function object that you pass into catcher could contain application state information.
so could ... class ExceptionHandler { int applicationState; public: void HandleException() { // same as the free function in last post } };
You could also use any functor that you happen to have around that has operator()(std::logic_error&), operator()(std::exception&), or operator()(void).
Right, but what can such a functor do better than ExceptionHandler::HandleException() above or ::HandleException() in the last post? Regards, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.

Jeremy Day wrote:
On 7/18/06, Andreas Huber <ahd6974-spamgroupstrap@yahoo.com> wrote:
How is your approach better than:
[snip]
Heh. Well, when you put it that way it probably isn't. However, the function object that you pass into catcher could contain application state information. You could also use any functor that you happen to have around that has operator()(std::logic_error&), operator()(std::exception&), or operator()(void).
additionally, this functor can be useful in a context where no exceptions are thrown at all - in filesystem functions with additional error_code parameter, if Beman'll eventually replace it with generic exception visitor approach.
Jeremy _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Hello Jeremy! You've come in the right place and in the right time. Your code is _very_ useful and is a great step forward in exception handling techniques. See my previous post with [system] in it's subject. after posting it I've thought further and caught the idea to use visitor pattern to handle exceptions in type-safe, re-usable and manageable way. but I've had no idea of how to implement it in current C++. So your code is very welcomed. put it in the vault section (you can find it on the main boost page) please. in filesystem error handling it can be used uniformly to handle errors in both cases where exception or additional parameter to indicate error is used: class my_exception_handler {...}; try { call_filesystem_lib(...); } catch(...) { catcher(my_exception_handler()); } or call_filesystem_lib(..., my_exception_handler()); //Note no error code is required Best, Oleg Abrosimov. Jeremy Day wrote:
On 7/18/06, Sohail Somani <s.somani@fincad.com> wrote:
I just don't see the point, except as an academic exercise
The point is partly academic, as I am working on learning MPL. However, I think that this technique, or some derivation thereof, can help make code more maintainable, since you can reuse my_exception_handler whenever you want to handle the same exception in the same way, even though you catch it in a different place. With catch blocks the only recourse, so far as I can tell, is to basically copy-and-paste the catch code to each location where you need the exception handling code.
Jeremy _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Oleg, I strongly suspect that it was your [system] message that got me thinking of this in the first place. I'll try to get the code polished up a bit more and put into the vault later today. Jeremy On 7/18/06, Oleg Abrosimov <beholder@gorodok.net> wrote:
Hello Jeremy!
You've come in the right place and in the right time. Your code is _very_ useful and is a great step forward in exception handling techniques. See my previous post with [system] in it's subject.
after posting it I've thought further and caught the idea to use visitor pattern to handle exceptions in type-safe, re-usable and manageable way. but I've had no idea of how to implement it in current C++. So your code is very welcomed. put it in the vault section (you can find it on the main boost page) please.
in filesystem error handling it can be used uniformly to handle errors in both cases where exception or additional parameter to indicate error is used:
class my_exception_handler {...};
try { call_filesystem_lib(...); } catch(...) { catcher(my_exception_handler()); }
or
call_filesystem_lib(..., my_exception_handler()); //Note no error code is required
Best, Oleg Abrosimov.
Jeremy Day wrote:
On 7/18/06, Sohail Somani <s.somani@fincad.com> wrote:
I just don't see the point, except as an academic exercise
The point is partly academic, as I am working on learning MPL. However, I think that this technique, or some derivation thereof, can help make code more maintainable, since you can reuse my_exception_handler whenever you want to handle the same exception in the same way, even though you catch it in a different place. With catch blocks the only recourse, so far as I can tell, is to basically copy-and-paste the catch code to each location where you need the exception handling code.
Jeremy _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Oleg, I just uploaded catcher to the Boost Vault. You can find it (catcher.hpp) along with VS7 project files at http://tinyurl.com/l6lt4 . Any comments that you have (or anyone else, for that matter) are more than welcome. Jeremy* *

On Wed, 19 Jul 2006 14:21:19 -0500, "Jeremy Day" <jeremy.day@gmail.com> wrote:
Oleg,
I just uploaded catcher to the Boost Vault. You can find it (catcher.hpp) along with VS7 project files at http://tinyurl.com/l6lt4 . Any comments that you have (or anyone else, for that matter) are more than welcome.
Sorry for not commenting on the library yet (no time :-() but I was struck by the file size. I suppose you can shrink it to 70/80 kB by removing all the "intermediate"/"temporary" files and the buildlog. -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

On 7/19/06, Gennaro Prota <gennaro_prota@yahoo.com> wrote:
Sorry for not commenting on the library yet (no time :-() but I was struck by the file size. I suppose you can shrink it to 70/80 kB by removing all the "intermediate"/"temporary" files and the buildlog.
Yikes! You're absolutely correct. I'll do that presently. Jeremy

Hello Jeremy! I'm not a metaprogramming expert, but I have one suggestion to imrove your implementation: replace static void execute(Iterator*, LastIterator*, F f) { typedef typename boost::mpl::deref<Iterator>::type item; try { throw; } //... } with static void execute(Iterator*, LastIterator*, F f) { assert(std::uncaught_exception()); typedef typename boost::mpl::deref<Iterator>::type item; try { throw; } //... } It prevents use of your catcher outside of any catch block. Actually, it is the first useful application of std::uncaught_exception() function that I'm aware of ;-) Now I'm more interested in the client side code - the visitor and code duplication here. It can be seen from another point - there is a coupling of exception handlers (operators in visitor) and types of exception that can be handled by catcher. We can have more freedom if client code would looks like this: //in application_exception_handler.hpp struct my_exception_handler { void operator()(std::string& sError); //Note here void operator()(std::exception& oError); void operator()(std::logic_error& oError); void operator()(void); }; //in application.cpp typedef boost::mpl::vector<std::logic_error, std::exception> exceptions; //Note here int main() try { throw std::logic_error("testing"); } catch(...) { catcher<exceptions>(my_exception_handler()); //Note here } with this transformation one can use one my_exception_handler class with many reduced exceptions typelists. It also eliminates the duplication problem. Duplication still exists but is intensional. Best, Oleg Abrosimov. Jeremy Day wrote:
Oleg,
I just uploaded catcher to the Boost Vault. You can find it (catcher.hpp) along with VS7 project files at http://tinyurl.com/l6lt4 . Any comments that you have (or anyone else, for that matter) are more than welcome.
Jeremy*
* _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Oleg Abrosimov wrote:
static void execute(Iterator*, LastIterator*, F f) { assert(std::uncaught_exception()); typedef typename boost::mpl::deref<Iterator>::type item;
try { throw; } //... }
uncaught_exception() always returns false in VC++6, so if you want the thing to work there you need to put this assert under conditionals. But actually, it will never work and always assert(). The standard says: *Returns:* true after completing evaluation of a /throw-expression/ until either completing initialization of the /exception-declaration/ in the matching handler or after entering terminate() for eny reason other than an explicit call to terminate(). [/Note:/ This includes stack unwinding --/end note/] At the point you enter execute(), the matching handler (the catch(...) outside) has completed initialization of its exception declaration. The use case for uncaught_exception() is quite simple: it allows destructors to take different actions depending on whether they're destructed due to stack unwind or a different reason. I've used it in a thin wrapper around jpeglib: there you have to wrap the encoding/decoding process in matching function calls, with different end calls depending on whether an error occurred. I wrote a sentry class that calls the start function on construction and uses uncaught_exception() to decide which of the end functions it should call on destruction. If the guarded block exits with an exception, the error abort function will be called, otherwise the normal decoding finished function will be called. Another option is for destructors that perform operations that could fail. They could throw an exception in case of that failure, unless they've determined, via uncaught_exception(), that an exception is already pending. Then they don't throw, to avoid terminate() being called. As a simple way of remembering when uncaught_exception() returns true, simply remember that this snippet will always call terminate() instead of actually throwing. if(uncaught_exception()) throw 1; Sebastian Redl

On 7/21/06, Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
The use case for uncaught_exception() is quite simple: it allows destructors to take different actions depending on whether they're destructed due to stack unwind or a different reason. I've used it in a thin wrapper around jpeglib: there you have to wrap the encoding/decoding process in matching function calls, with different end calls depending on whether an error occurred.
I have done a similar thing with uncaught_exception(). I have a wrapper around a series of database primatives, and my destructor looks something like this: database_wrapper::~database_wrapper(void) { if(std::uncaught_exception()) { //Something went wrong, and I cannot be certain that the state of the transaction is valid. rollback_transaction(); } else { //My wrapper is being destroyed on account of leaving scope, so the transaction is good. commit_transaction(); } } This type of activity is very common in any object involved in the oddly name Resource Acquisition is Initialization (RAII) idiom. Jeremy

On 7/20/06, Oleg Abrosimov <beholder@gorodok.net> wrote:
//in application_exception_handler.hpp struct my_exception_handler { void operator()(std::string& sError); //Note here void operator()(std::exception& oError); void operator()(std::logic_error& oError); void operator()(void); };
//in application.cpp typedef boost::mpl::vector<std::logic_error, std::exception> exceptions; //Note here
int main() try { throw std::logic_error("testing"); } catch(...) { catcher<exceptions>(my_exception_handler()); //Note here }
with this transformation one can use one my_exception_handler class with many reduced exceptions typelists. It also eliminates the duplication problem. Duplication still exists but is intensional.
I have considered doing that, but I haven't yet had the time to actually get it done. I would like to use a provided exception list and, if one is not provided, look for a nested exceptions type. By the way, I don't know if I have said this yet or not, but one of my primary motivations for tinkering around with this in the first place is sheer laziness. I don't like to write more than one catch block if I can absolutely help it. Jeremy

All, Sorry for the rather long delay. I've been meaning to get back to this, but I haven't had time until now. I just uploaded a new version of the catcher to the Vault. You can find it here: http://tinyurl.com/hrdm6 . On 7/20/06, Oleg Abrosimov <beholder@gorodok.net> wrote:
int main() try { throw std::logic_error("testing"); } catch(...) { catcher<exceptions>(my_exception_handler()); //Note here }
with this transformation one can use one my_exception_handler class with many reduced exceptions typelists. It also eliminates the duplication problem. Duplication still exists but is intensional.
I spent a few minutes experimenting. Before I just had this little function: template <typename ExceptionHandler> void catcher(ExceptionHandler& oHandler) { catcher_while_<ExceptionHandler::exceptions>(oHandler); } Per Oleg's suggestion I added an additional function, which looks like this: template <typename Exceptions, typename ExceptionHandler> void catcher(ExceptionHandler& oHandler) { catcher_while_<Exceptions>(oHandler); } Now if ExceptionHandler has a nested exceptions type you don't need to do something along the lines of catcher<my_exceptions>(my_exception_handler()). However, if you want to avoid coupling the exceptions with the handler you can have them separate. Here is the full example from General_Catcher.cpp. #include "catcher.hpp" #include <iostream> #include <boost/mpl/vector.hpp> struct my_exception_handler { typedef boost::mpl::vector<std::logic_error, std::exception> exceptions; void operator()(std::exception& oError) { std::cout << "my_exception_handler::operator()(std::exception&)" << std::endl; } //end of void operator()(std::exception& oError) void operator()(std::logic_error& oError) { std::cout << "my_exception_handler::operator()(std::logic_error&)" << std::endl; } //end of void operator()(std::logic_error& oError) void operator()(void) { std::cout << "my_exception_handler::operator()(void)" << std::endl; } //end of void operator()(void) }; //end of struct my_exception_handler struct my_exception_handler2 { void operator()(std::exception& oError) { std::cout << "my_exception_handler2::operator()(std::exception&)" << std::endl; } //end of void operator()(std::exception& oError) void operator()(std::logic_error& oError) { std::cout << "my_exception_handler2::operator()(std::logic_error&)" << std::endl; } //end of void operator()(std::logic_error& oError) void operator()(void) { std::cout << "my_exception_handler2::operator()(void)" << std::endl; } //end of void operator()(void) }; //end of struct my_exception_handler int main(int argc, char* argv[]) { try { throw(std::logic_error("testing")); } //end of try block catch(...) { catcher(my_exception_handler()); } //end of catch(...) block try { throw(std::exception("testing")); } //end of try block catch(...) { catcher(my_exception_handler()); } //end of catch(...) block try { throw("testing"); } //end of try block catch(...) { catcher(my_exception_handler()); } //end of catch(...) block typedef boost::mpl::vector<std::logic_error, std::exception> exceptions; try { throw(std::logic_error("testing")); } //end of try block catch(...) { catcher<exceptions>(my_exception_handler2()); } //end of catch(...) block try { throw(std::exception("testing")); } //end of try block catch(...) { catcher<exceptions>(my_exception_handler2()); } //end of catch(...) block try { throw("testing"); } //end of try block catch(...) { catcher<exceptions>(my_exception_handler2()); } //end of catch(...) block return(0); } //end of int main(int argc, char* argv[])

Jeremy Day wrote:
[snip] Now if ExceptionHandler has a nested exceptions type you don't need to do something along the lines of catcher<my_exceptions>(my_exception_handler()). However, if you want to avoid coupling the exceptions with the handler you can have them separate.
Here is the full example from General_Catcher.cpp.
#include "catcher.hpp" #include <iostream> #include <boost/mpl/vector.hpp>
[snip]
int main(int argc, char* argv[]) { typedef boost::mpl::vector<std::logic_error, std::exception> exceptions;
try { throw(std::logic_error("testing")); } //end of try block catch(...) { catcher<exceptions>(my_exception_handler2()); } //end of catch(...) block [snip] } //end of int main(int argc, char* argv[])
Hello, Jeremy! Thank you for your involvement in this topic. I'm very interested in pushing it to a complete solution one day. one further improvement I see is to define simple macros to eliminate some details from client code. something like this would be appropriate: try { throw std::logic_error("testing"); } BOOST_CATCH(my_exception_handler()); and try { throw std::logic_error("testing"); } BOOST_CATCH_EX(exceptions, my_exception_handler()); and of course, I agree with David Abrahams that exceptions typelist should be sorted to handle most derived first. boost::is_base_of<Base, Derived> from type_traits library can be used to achieve it. One more idea to improve maintainability of client code: class my_exceptions_handler { BOOST_DEFINE_EXCEPTION_HANDLER_FIRST(exception_type, exception_variable, 1) { //code here } BOOST_DEFINE_EXCEPTION_HANDLER(exception_type2, exception_variable, 1, 2) { //code here } BOOST_DEFINE_EXCEPTION_HANDLER(exception_type2, exception_variable, 2, 3) { //code here } BOOST_DEFINE_EXCEPTION_HANDLER_LAST(exception_type, exception_variable, 3) { //code here } }; These macros automatically define exceptions list eliminating last piece of code duplication. numbers are used to decorate typelist' name that is already defined. Best, Oleg Abrosimov.

On 7/27/06, Oleg Abrosimov <beholder@gorodok.net> wrote:
one further improvement I see is to define simple macros to eliminate some details from client code. something like this would be appropriate:
try { throw std::logic_error("testing"); } BOOST_CATCH(my_exception_handler());
and
try { throw std::logic_error("testing"); } BOOST_CATCH_EX(exceptions, my_exception_handler());
Good suggestions. Done and done. and of course, I agree with David Abrahams that exceptions typelist
should be sorted to handle most derived first. boost::is_base_of<Base, Derived> from type_traits library can be used to achieve it.
Also a good suggestion. Until last night I wasn't sure exactly how to handle this, but I figured it out. One more idea to improve maintainability of client code:
class my_exceptions_handler { BOOST_DEFINE_EXCEPTION_HANDLER_FIRST(exception_type, exception_variable, 1) { //code here } BOOST_DEFINE_EXCEPTION_HANDLER(exception_type2, exception_variable, 1, 2) { //code here } BOOST_DEFINE_EXCEPTION_HANDLER(exception_type2, exception_variable, 2, 3) { //code here } BOOST_DEFINE_EXCEPTION_HANDLER_LAST(exception_type, exception_variable, 3) { //code here } };
These macros automatically define exceptions list eliminating last piece of code duplication. numbers are used to decorate typelist' name that is already defined.
I'm not sure that I understand the need for the _FIRST and _LAST versions of the BOOST_DEFINE_EXCEPTION_HANDLER macro. I also don't understand why I need to decorate the typelist's name. If you have some pseudocode in mind for the definitions of BOOST_DEFINE_EXCEPTION_HANDER_FIRST, BOOST_DEFINE_EXCEPTION_HANDER, and BOOST_DEFINE_EXCEPTION_HANDER_LAST I'd be happy to look into this. As it stands now there is a new version of Boost Catcher in the vault. I added the BOOST_CATCH macros and the exception sorting. Comments are welcome and encouraged. Jeremy

Jeremy Day wrote:
One more idea to improve maintainability of client code:
class my_exceptions_handler { BOOST_DEFINE_EXCEPTION_HANDLER_FIRST(exception_type, exception_variable, 1) { //code here } BOOST_DEFINE_EXCEPTION_HANDLER(exception_type2, exception_variable, 1, 2) { //code here } BOOST_DEFINE_EXCEPTION_HANDLER(exception_type2, exception_variable, 2, 3) { //code here } BOOST_DEFINE_EXCEPTION_HANDLER_LAST(exception_type, exception_variable, 3) { //code here } };
These macros automatically define exceptions list eliminating last piece of code duplication. numbers are used to decorate typelist' name that is already defined.
I'm not sure that I understand the need for the _FIRST and _LAST versions of the BOOST_DEFINE_EXCEPTION_HANDLER macro. I also don't understand why I need to decorate the typelist's name. If you have some pseudocode in mind for the definitions of BOOST_DEFINE_EXCEPTION_HANDER_FIRST, BOOST_DEFINE_EXCEPTION_HANDER, and BOOST_DEFINE_EXCEPTION_HANDER_LAST I'd be happy to look into this.
Note different number of arguments in these macros. It describes need for BOOST_DEFINE_EXCEPTION_HANDLER_FIRST. it defines handler and typedef for exceptions typelist with name decorated by its last argument. (with BOOST_PP_CAT(A, B) macro) BOOST_DEFINE_EXCEPTION_HANDLER defines handler and defines a typedef that extends (with mpl stuff) typedef generated by BOOST_DEFINE_EXCEPTION_HANDLER_FIRST macro. Its third parameter is used to restore the last defined exceptions typelist's name and last parameter is used to decorate name of typelist generated by it's own. BOOST_DEFINE_EXCEPTION_HANDLER_LAST defines the final exceptions typedef. It doesn't needs parameter to decorate it, only one to know a name of the last defined typelist name. Note, that parameters mentioned are not restricted to be numbers, but any sequence of numbers, letters and underscores. Hope it helps. Best, Oleg Abrosimov.

Oleg Abrosimov wrote:
Thank you for your involvement in this topic. I'm very interested in pushing it to a complete solution one day.
one further improvement I see is to define simple macros to eliminate some details from client code. something like this would be appropriate:
try { throw std::logic_error("testing"); } BOOST_CATCH(my_exception_handler());
I'd changed BOOST_CATCH to something less generic.
try { throw std::logic_error("testing"); } BOOST_CATCH_EX(exceptions, my_exception_handler());
Well, if it's macro, why not just generate handle-seq (a list of catch clauses) rather then catch(...) { handle(); throw; } ? For example: try { throw std::logic_error("testing"); } BOOST_CATCH_PP_SEQ((ex1)(ex2)(ex3), my_exception_handler()); You could even pass mpl sequence to a macro if you know a size of the sequence: try { throw std::logic_error("testing"); } BOOST_CATCH_MPL_SEQ(3, mpl::vector<ex1,ex2,ex3>, func); This could be expanded to try { throw std::logic_error("testing"); } catch(mpl::at<mpl::vector<ex1,ex2,ex3>,0>::type const& ex) { BOOST_STATIC_ASSERT(( 3 == mpl::size<mpl::vector<ex1,ex2,ex3> >::type::value)); func(ex); } catch(mpl::at<mpl::vector<ex1,ex2,ex3>,1>::type const& ex) { func(ex); } catch(mpl::at<mpl::vector<ex1,ex2,ex3>,2>::type const& ex) { func(ex); } -- Alexander Nasonov

On 7/27/06, Alexander Nasonov <alnsn@yandex.ru> wrote:
Well, if it's macro, why not just generate handle-seq (a list of catch clauses) rather then catch(...) { handle(); throw; } ?
There are two reasons, really. The first reason is that it isn't something that I have considered before. I have spent essentially zero time looking at the preprocessor library. The second reason is that using the preprocessor just doesn't seem as much fun. I will explore that idea, though, since it is something that I don't have much experience with. Jeremy

Jeremy Day wrote:
There are two reasons, really. The first reason is that it isn't something that I have considered before. I have spent essentially zero time looking at the preprocessor library. The second reason is that using the preprocessor just doesn't seem as much fun. I will explore that idea, though, since it is something that I don't have much experience with.
Believe me, Boost.Preprocessor is fun. Overusing it is not fun but it's a more general principle that can be applied to many other C++ features. PP is especially good for libraries. Two reasons why I would consider PP version: 1. catch(...) followed by rethrow might be less efficient than handle-seq. I never measured this, though. 2. catch(...) catches too many things on some compilers. I know only one (very popular) compiler that also catches system exceptions (aka SEH). Though, I don't remember how it rethrows those exceptions. Another possible problem is that a stack trace of original throw instruction might be replaced with subsequent throw inside catch(...). It has been discussed in this thread but only for few compilers, IIRC. -- Alexander Nasonov

On 7/27/06, Alexander Nasonov <alnsn@yandex.ru> wrote:
1. catch(...) followed by rethrow might be less efficient than handle-seq. I never measured this, though.
I'm not sure exactly what sorts of inlining compilers can do with code like I'm using to catch and rethrow (which is very similar to mpl::for_each, since I copied the methodology almost exactly), so I'd be almost positive that the preprocessor approach would be more efficient. I'd love to be proven wrong, though. I do have one concern about the preprocessor approach, though. Could the user give the preprocessor a sequence, such as mpl::vector<std::exception, std::logic_error>, and have that sequence sorted to mpl::vector<std::logic_error, std::exception> internally to the preprocessor macro? I'm automatically sorting the sequence in the code that I have now. 2. catch(...) catches too many things on some compilers. I know only one
(very popular) compiler that also catches system exceptions (aka SEH). Though, I don't remember how it rethrows those exceptions.
It seems like catching SEH exceptions could be a good thing. I would certainly like for ALL exceptions, whether they C or C++ exceptions, to go through the same machinery. I can imagine that not everyone feels this way, though. Jeremy

Jeremy Day wrote:
It seems like catching SEH exceptions could be a good thing. I would certainly like for ALL exceptions, whether they C or C++ exceptions, to go through the same machinery. I can imagine that not everyone feels this way, though.
Please, NO! It's my experience that one catch(...) in a program may be a source of many annoying glitches that users report periodically but developers don't understand what's going on. Removing this often helps. Users start reporting crashes. Most difficult at this stage is to find a user who is able to run Dr. Watson, check 'Create Crash Dump File' and send a dump to developers :) Also worth noting that SEH is not standard C/C++. -- Alexander Nasonov

Alexander Nasonov wrote:
try { throw std::logic_error("testing"); } BOOST_CATCH(my_exception_handler());
I'd changed BOOST_CATCH to something less generic.
Why? boost doesn't have such a macro till now. For me it means that there was no need in such a generic facility and it can be concluded that a chance for name clash in future is only theoretical here. From other point actual meaning of this macro is "catch and handle" but BOOST_CATCH_AND_HANDLE is too verbose for me. I believe that BOOST_CATCH is good enough. It is a compromise between user-friendliness and brevity. Fill free to suggest something if you are not convinced yet.
try { throw std::logic_error("testing"); } BOOST_CATCH_EX(exceptions, my_exception_handler());
Well, if it's macro, why not just generate handle-seq (a list of catch clauses) rather then catch(...) { handle(); throw; } ?
For example:
try { throw std::logic_error("testing"); } BOOST_CATCH_PP_SEQ((ex1)(ex2)(ex3), my_exception_handler());
You could even pass mpl sequence to a macro if you know a size of the sequence:
try { throw std::logic_error("testing"); } BOOST_CATCH_MPL_SEQ(3, mpl::vector<ex1,ex2,ex3>, func);
This could be expanded to
try { throw std::logic_error("testing"); } catch(mpl::at<mpl::vector<ex1,ex2,ex3>,0>::type const& ex) { BOOST_STATIC_ASSERT(( 3 == mpl::size<mpl::vector<ex1,ex2,ex3> >::type::value)); func(ex); } catch(mpl::at<mpl::vector<ex1,ex2,ex3>,1>::type const& ex) { func(ex); } catch(mpl::at<mpl::vector<ex1,ex2,ex3>,2>::type const& ex) { func(ex); }
Interesting, but complicates usage. Note that in BOOST_CATCH macro exceptions_handler() defines typedef ... exceptions; but in you version of BOOST_CATCH_EX macro it is defined as a PP sequence. Why two ways to do the same thing? There should be a very good reason to add such a functionality. Yes, only add, not replace current. average user like me ;-) should be isolated from PP sequences. They are good for library internals, not for interface IMO. Alexander Nasonov wrote:
Two reasons why I would consider PP version:
1. catch(...) followed by rethrow might be less efficient than
handle-seq. I never measured this, though. boost::filesystem has two versions of all functions that could generate exceptions. reason is clear - in performance critical applications one can not use exception machinery because the cost of stack unwinding is not acceptable. My contra-point here is that one shouldn't use exceptions if performance is too important for this particular piece of code.
2. catch(...) catches too many things on some compilers. I know only one (very popular) compiler that also catches system exceptions (aka SEH). Though, I don't remember how it rethrows those exceptions.
Seems that we are both not very knowledgeable in this area. I remember that SEH handling is done in boost::test library. So, maybe Gennadiy Rozental can shed some light here? Best, Oleg Abrosimov.

Oleg Abrosimov wrote:
Why? boost doesn't have such a macro till now. For me it means that there was no need in such a generic facility and it can be concluded that a chance for name clash in future is only theoretical here. From other point actual meaning of this macro is "catch and handle" but BOOST_CATCH_AND_HANDLE is too verbose for me. I believe that BOOST_CATCH is good enough. It is a compromise between user-friendliness and brevity. Fill free to suggest something if you are not convinced yet.
Boost is close to the standard and some libraries implement functionality that will be replaced with C++ core feature one day. For example: BOOST_TYPEDEF -> typedef BOOST_FOREACH -> foreach My first reaction on BOOST_CATCH was that it's a replacement or improved version C++'s catch. So, this patterns BOOST_${C++200x keyword} is accosiated with pure library implementation of proposed keyword and this pattern BOOST_${C++98 keyword} is accosiated with improved version of some existing keyword. -- Alexander Nasonov

On 18/07/06, Sohail Somani <s.somani@fincad.com> wrote:
I just don't see the point, except as an academic exercise
I used a similar technique when I wrote a subset of some of Kevlin Henney's threading concepts [1]. I wanted to extend it so exceptions could be propagated from the thread function to the calling thread. The client code looked like this : // code begins... std::string my_function(); joiner<std::string> joiner = thread(my_function, catch_<std::runtime_error, my_app_specific_error>()); // parallel work here std::string result = joiner(); // ...ends joiner::operator() may throw std::runtime_error, my_app_specific_error, or std::bad_exception if the exception could not be mapped. Of course exceptions are sliced, but support could be added for cloning if the exception hierarchy supported it (through ADL perhaps). Anyway, I make use of it quite a bit and I've never found the slicing to be a problem - typically you know what you expect to catch So I can see at least one non-academic use for it. Sam [1] http://www.two-sdg.demon.co.uk/curbralan/papers/accu/MoreC++Threading.pdf
participants (9)
-
Alexander Nasonov
-
Andreas Huber
-
Dean Michael Berris
-
Gennaro Prota
-
Jeremy Day
-
Oleg Abrosimov
-
Sam Partington
-
Sebastian Redl
-
Sohail Somani