
Hello, After the promising initial interest in the Exception lib I wrote, I ported the source code to Boost, and posted a link to the documentation. But so far there has not been even a single reply to my post :| I am not quite sure how to inerpret this... Is it "go ahead, we'll discuss the details during the formal review process"? Or is it complete lack of interest for adding such a library to Boost? I'm even more puzzled because my initial post did get a bunch of responses, without even having posted source code or documentation! Anyway... Here is the link to the documentation again: http://www.revergestudios.com/exception/exception.htm If you click "download", you'll get the source code, as well as an example and a test suite, complete with Boost Build jamfiles. Thanks, Emil

On 7/3/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
I am not quite sure how to inerpret this... Is it "go ahead, we'll discuss the details during the formal review process"? Or is it complete lack of interest for adding such a library to Boost?
I just read through a good part of the documentation, and I see good potential uses for this library. I have a couple of concerns though, please see below...
Anyway... Here is the link to the documentation again:
http://www.revergestudios.com/exception/exception.htm
If you click "download", you'll get the source code, as well as an example and a test suite, complete with Boost Build jamfiles.
I haven't downloaded the files yet, but am planning to test them out soon. I have a few questions though, which you might be able to address: 1) use of dynamic_cast in the following snippet: catch( read_error & x ) { if( exception_info * xi = dynamic_cast<exception_info *>(&x) ) if( exception_errno * err = get_errno(*xi) ) ....; //err->code() is the captured errno. //err->strerror() is the corresponding error string. } Perhaps this will be a major barrier to adoption, since it reads more like a kludge than a way of exposing a well-thought about interface. This also seems like too much work for exception handling -- which seems harder to do than just creating my own exception class which derives from std::exception, and then a custom constructor that contains a copy of the information object that I know I want to be available from those that will be receiving the exception. Is there a good reason why you're not using a "composite-style" [see GoF composite pattern] exception if you intend to be able to add information as the exception is propagated through the try {} catch(...) {} blocks? 2) Have you considered using Boost.Fusion to create mappings of compile-time types to runtime values so that you can access the information objects in a type-safe manner? I'm not an expert about it, but it might be easier to do something like: catch (exception_info & x) { my_type temp = at_key<my_type>(x.objects); }; Wherein `x.objects` is a Boost.Fusion map, and allows you to map values to types? Perhaps you can come up with another way of avoiding the use of dynamic_cast<>() but with what you're trying to achieve, I think Boost.Fusion will definitely be able to help you out with the interface part. I think I have more questions, but I will reserve them when either the library gets scheduled for formal review, or when I actually get the time to test out the available implementation. But generally, on my part I am interested in this library. -- 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

Dean,
1) use of dynamic_cast in the following snippet:
catch( read_error & x ) { if( exception_info * xi = dynamic_cast<exception_info *>(&x) ) if( exception_errno * err = get_errno(*xi) ) ....; //err->code() is the captured errno. //err->strerror() is the corresponding error string. }
Perhaps this will be a major barrier to adoption, since it reads more like a kludge than a way of exposing a well-thought about interface.
Would you be happy if the dynamic_cast is hidden in a function? I don't think it can be completely avoided. If you throw failed<foo>, you should catch(foo &) to handle the exception. At this point you do need a dynamic_cast to get to the exception_info sub-object. You could have a virtual function in foo to get you an exception_info *, but I don't think that this is appropriate.
This also seems like too much work for exception handling -- which seems harder to do than just creating my own exception class which derives from std::exception, and then a custom constructor that contains a copy of the information object that I know I want to be available from those that will be receiving the exception.
When you say that you can just create your own exception class, do you mean that you'd create a different exception class for each combination of context information you want to bundle in it?
Is there a good reason why you're not using a "composite-style" [see GoF composite pattern] exception if you intend to be able to add information as the exception is propagated through the try {} catch(...) {} blocks?
If you catch(...), you can't do anything to the exception object. That's why you need class exception_info: so you can catch(exception_info&) and add info to it, regardless of T in a throw failed<T>(). Or did you mean to use composite pattern to organize the information in an exception_info? Could you illustrate this with an example?
2) Have you considered using Boost.Fusion to create mappings of compile-time types to runtime values so that you can access the information objects in a type-safe manner? I'm not an expert about it, but it might be easier to do something like:
catch (exception_info & x) { my_type temp = at_key<my_type>(x.objects); };
I have to check Boost.Fusion out, but from your code above it seems to me it would be directly applicable. That's exactly what exception_info::get does: you pass it a type, it gets you a reference to the object of the specified type stored in the exception_info. --Emil

On 7/4/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
I don't think it can be completely avoided. If you throw failed<foo>, you should catch(foo &) to handle the exception. At this point you do need a dynamic_cast to get to the exception_info sub-object. You could have a virtual function in foo to get you an exception_info *, but I don't think that this is appropriate.
Let's see: template <typename _T> class failed : public exception_info, public std::exception { public: failed() { }; explicit failed (const _T & e) : _wrapped_exception(e) { }; // ... other common methods ... }; //... try { ... } catch (exception_info & e) { ... } where `e` is already an exception_info reference.
This also seems like too much work for exception handling -- which seems harder to do than just creating my own exception class which derives from std::exception, and then a custom constructor that contains a copy of the information object that I know I want to be available from those that will be receiving the exception.
When you say that you can just create your own exception class, do you mean that you'd create a different exception class for each combination of context information you want to bundle in it?
Granted that the idea is that the exceptions themselves will be designed by me, and that I know what code will require what information, it sounds like a reasonable way of going about it -- compared to doing a dynamic_cast all the time, and the interface being not so clear and "developer friendly".
Is there a good reason why you're not using a "composite-style" [see GoF composite pattern] exception if you intend to be able to add information as the exception is propagated through the try {} catch(...) {} blocks?
If you catch(...), you can't do anything to the exception object. That's why you need class exception_info: so you can catch(exception_info&) and add info to it, regardless of T in a throw failed<T>(). Or did you mean to use composite pattern to organize the information in an exception_info? Could you illustrate this with an example?
I meant for general catch blocks, I didn't intend to say that the literal catch(...) {} blocks. Something like this: struct composite_exception { std::vector<composite_exception> _exceptions; void add(const composite_exception & e) { _exceptions.add(composite_exception(e)); } explicit composite_exception(const composite_exception & other) : _exceptions(other._exceptions) { }; composite_exception() {}; // add common methods here, like "what()" }; So you can do something like: try { } catch (composite_exception & e) { //... iterate through the vector }; -- 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

Dean Michael Berris wrote:
On 7/4/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
I don't think it can be completely avoided. If you throw failed<foo>, you should catch(foo &) to handle the exception. At this point you do need a dynamic_cast to get to the exception_info sub-object. You could have a virtual function in foo to get you an exception_info *, but I don't think that this is appropriate.
Let's see:
template <typename _T> class failed : public exception_info, public std::exception { public: failed() { }; explicit failed (const _T & e) : _wrapped_exception(e) { };
// ... other common methods ... };
//... try { ... } catch (exception_info & e) { ... }
But the whole point is that in some scenarios you want to catch T, not exception_info. You are interested in a read_error and have an appropriate response to it ready, but the rest of the exceptions must be propagated unharmed. So you catch( read_error const & r ) and use dynamic_cast to see whether it also contains exception_info. Obviously, if you want to catch all exceptions regardless of type, there is no need for a dynamic_cast. You catch exception_info, std::exception, and ... (in that order.)

On 7/5/06, Peter Dimov <pdimov@mmltd.net> wrote:
But the whole point is that in some scenarios you want to catch T, not exception_info. You are interested in a read_error and have an appropriate response to it ready, but the rest of the exceptions must be propagated unharmed.
So you catch( read_error const & r ) and use dynamic_cast to see whether it also contains exception_info.
Now I get it. Is there any other way of doing it than dynamic_cast'ing the exception then? I would like to be able to use this in the future too, but the single thing that's making me not want to use it is the use of dynamic_cast -- and somehow, something deep in me wants to come up with a less explicit, but more user-friendly way of doing so. -- 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

Dean Michael Berris wrote:
On 7/5/06, Peter Dimov <pdimov@mmltd.net> wrote:
But the whole point is that in some scenarios you want to catch T, not exception_info. You are interested in a read_error and have an appropriate response to it ready, but the rest of the exceptions must be propagated unharmed.
So you catch( read_error const & r ) and use dynamic_cast to see whether it also contains exception_info.
Now I get it.
Is there any other way of doing it than dynamic_cast'ing the exception then?
You need the dynamic_cast, because all you have is a read_error pointer, and you need an exception_info pointer *if* it is available. For one reason or another, the program could throw a "naked" read_error object (as opposed to using throw failed<read_error>()) and in this case you will not have an exception_info sub-object in the exception. The reason why I have not hidden the dynamic_cast in a function get_exception_info() is that the only implementation possible is through a dynamic_cast, so why bother. --Emil

On 7/6/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
You need the dynamic_cast, because all you have is a read_error pointer, and you need an exception_info pointer *if* it is available. For one reason or another, the program could throw a "naked" read_error object (as opposed to using throw failed<read_error>()) and in this case you will not have an exception_info sub-object in the exception.
The reason why I have not hidden the dynamic_cast in a function get_exception_info() is that the only implementation possible is through a dynamic_cast, so why bother.
How about using preprocessor macro's to hide this? Something like a BOOST_EXCEPTION_INFO(exception_reference, exception_info_handle) which abstracts the fact that you use dynamic_cast<> to return an exception_info_handle ? The following would look "cleaner": try { } catch (read_error & e) { BOOST_EXCEPTION_INFO(e, info); if (info) { // use the info object, otherwise this doesn't get executed } //.. handle exception normally } A templates only approach would be something like: try { } catch (read_error & e) { extract_info<read_error> info(e); if (info) { // if e was a failed<> wrapped exception, info is defined // and can be accessed -- therefore this block will be executed } // deal with exception accordingly } This way, if in case there's a different way of accessing the exception info subobject (or internal reference, or some other methodology in case the design changes in the future), there's an interface to abstract the details of extracting the information object from the more important implementation. It's probably a personal issue against the use of dynamic_cast<> or static_cast<> and even const_cast<> because IMHO it makes code terribly un-readable and even seem "hackish". It's my personal opinion that whenever you need to resort to casting in client code, then that means the design of the solution isn't as elegant or as well thought out as it could be. -- 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

Dean Michael Berris wrote:
On 7/4/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
I don't think it can be completely avoided. If you throw failed<foo>, you should catch(foo &) to handle the exception. At this point you do need a dynamic_cast to get to the exception_info sub-object. You could have a virtual function in foo to get you an exception_info *, but I don't think that this is appropriate.
Let's see:
template <typename _T> class failed : public exception_info, public std::exception { public: failed() { }; explicit failed (const _T & e) : _wrapped_exception(e) { };
// ... other common methods ... };
//... try { ... } catch (exception_info & e) { ... }
where `e` is already an exception_info reference.
Yes, but that's how it's done in the exception lib when the exception is caught in otherwise exception-neutral contexts, only for the purpose to add info to it; no need for dynamic_cast there. But when you handle the exception, you shouldn't catch exception_info &, you should catch T (from your example). And now you need dynamic_cast to get to the exception_info sub-object.
This also seems like too much work for exception handling -- which seems harder to do than just creating my own exception class which derives from std::exception, and then a custom constructor that contains a copy of the information object that I know I want to be available from those that will be receiving the exception.
When you say that you can just create your own exception class, do you mean that you'd create a different exception class for each combination of context information you want to bundle in it?
Granted that the idea is that the exceptions themselves will be designed by me, and that I know what code will require what information, it sounds like a reasonable way of going about it -- compared to doing a dynamic_cast all the time, and the interface being not so clear and "developer friendly".
But that's far from granted! Consider this example: void copy_file( char const * name1, char const * name2 ) { boost::shared_ptr<FILE> f1 = my_fopen(name1,"rb"); boost::shared_ptr<FILE> f2 = my_fopen(name2,"wb"); try { my_fread( buf, 1, buf_size, f1 ); //throws by failed<file_read_error>(); my_fwrite( buf, 1, buf_size, f2 ); //throws by failed<file_write_error>(); } catch( exception_info & xi ) { xi << wrap_string<source_name>(name1) << wrap_string<destination_name>(name2); throw; } } OK, you are the designer of the my_fread and my_fwrite functions, and the file_read_error and file_write_error exceptions they throw. How do you know that a user will use them in a copy operation? You can't provide for storing a source and target file name in the exception objects without knowing that, can you? This is why the exception lib is necessary, because the context information is really that: context information. It depends on the context in which the code that throws is being called, and is out of your control and beyond your knowledge. The idea is to always use the failed function template when throwing, even if you don't have info to add to the exception at the point of the throw. This way you enable higher stack loations to add context information by catching you as exception_info &.
Is there a good reason why you're not using a "composite-style" [see GoF composite pattern] exception if you intend to be able to add information as the exception is propagated through the try {} catch(...) {} blocks?
If you catch(...), you can't do anything to the exception object. That's why you need class exception_info: so you can catch(exception_info&) and add info to it, regardless of T in a throw failed<T>(). Or did you mean to use composite pattern to organize the information in an exception_info? Could you illustrate this with an example?
I meant for general catch blocks, I didn't intend to say that the literal catch(...) {} blocks. Something like this:
struct composite_exception { std::vector<composite_exception> _exceptions; void add(const composite_exception & e) { _exceptions.add(composite_exception(e)); }
explicit composite_exception(const composite_exception & other) : _exceptions(other._exceptions) { };
composite_exception() {};
// add common methods here, like "what()" };
So you can do something like:
try { } catch (composite_exception & e) { //... iterate through the vector };
But by catching composite_exception &, you are really using value semantics to handle the exception. It's like sayng that you can always throw integer error codes, then catch( int ), and do a switch-case on the error code. In C++, we use types (not values) to differentiate between the different types of errors. The exception lib does not violate this principle: the value semantics of class exception_info are not intended for figuring out how to respond to the exception. When you throw failed<foo>(), you would catch(foo &) (or any of its public base types) to handle the exception; the exception_info sub-object is there only to provide context information, such as file names or whatever else makes sense for the user to see. --Emil

On 7/5/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
But when you handle the exception, you shouldn't catch exception_info &, you should catch T (from your example). And now you need dynamic_cast to get to the exception_info sub-object.
Yeah... Now I'm still thinking of perhaps another way within the current C++ limits of how to be able to do that (get the exception_info sub-object, or at least a handle to it) without having to do a dynamic_cast.
Granted that the idea is that the exceptions themselves will be designed by me, and that I know what code will require what information, it sounds like a reasonable way of going about it -- compared to doing a dynamic_cast all the time, and the interface being not so clear and "developer friendly".
But that's far from granted! Consider this example:
<example snipped>
OK, you are the designer of the my_fread and my_fwrite functions, and the file_read_error and file_write_error exceptions they throw. How do you know that a user will use them in a copy operation? You can't provide for storing a source and target file name in the exception objects without knowing that, can you?
Yeah... I never thought of it that way though -- I think I've always just exposed all the possible information that the exception handlers will want to get (which I always realize is such a waste too) by throwing really "fat" exceptions. But even then, it now still seems inadequate without using a facility such as the exception lib.
This is why the exception lib is necessary, because the context information is really that: context information. It depends on the context in which the code that throws is being called, and is out of your control and beyond your knowledge. The idea is to always use the failed function template when throwing, even if you don't have info to add to the exception at the point of the throw. This way you enable higher stack loations to add context information by catching you as exception_info &.
Okay, now that makes sense. :)
I meant for general catch blocks, I didn't intend to say that the literal catch(...) {} blocks. Something like this:
<sample snipped> But by catching composite_exception &, you are really using value semantics to handle the exception. It's like sayng that you can always throw integer error codes, then catch( int ), and do a switch-case on the error code.
In C++, we use types (not values) to differentiate between the different types of errors. The exception lib does not violate this principle: the value semantics of class exception_info are not intended for figuring out how to respond to the exception. When you throw failed<foo>(), you would catch(foo &) (or any of its public base types) to handle the exception; the exception_info sub-object is there only to provide context information, such as file names or whatever else makes sense for the user to see.
Agreed. Now it's clearer to me. Thanks for the clarifications, they are very much appreciated. Now if there's only a way of bypassing dynamic_cast in this situation... -- 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

After the promising initial interest in the Exception lib I wrote, I ported the source code to Boost, and posted a link to the documentation. But so far there has not been even a single reply to my post :|
Hello, I found the idea very appealing, I just didnt come around to review it yet. Here are my comments: - I don't like the word failed as in 'throw failed<my_error>' it seems strange to throw a "failed error", that's the way I read it anyway. I can't come up with a better one right now though. - There should be a way to iterate over all exception_info objects contained. This is useful in a case where you don't know what information was attached to the exception. Then you just want to print everything that can be translated via lexical_cast to a logfile to get the maximum information on the exception regardless. - The file read error example under "Adding strings" in the docs should be mentioned much earlier in the text. Because this is I believe a very common scenario. And it's always good to start with a simple example. - I don't think it's a good idea to have a tag mechanism to access each info field. It's inconvenient having to declare the tag. Of course strings can be abused.. but that's C++. I believe simple string keys are enough and very descriptive and easy to use. - why not create an operator << () that automatically does the wrapping via exception_info_wrapper instead of having a wrap_string(), wrap_errno()... - I don't like the dynamic_cast involved in getting the info object. It may be enough to hide it in a small inline function if (exception_info* xi = get_exception_info(&x)) _________________________________________________________________ Express yourself instantly with MSN Messenger! Download today it's FREE! http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/

Kevin Sopp wrote:
- There should be a way to iterate over all exception_info objects contained. This is useful in a case where you don't know what information was attached to the exception. Then you just want to print everything that can be translated via lexical_cast to a logfile to get the maximum information on the exception regardless.
For logging purposes, it might also be useful to be able to add several exception info entries of the same category and then iterate over them; in particular, I'm thinking of "poor man's" stack backtrace.

Kevin,
- I don't like the word failed as in 'throw failed<my_error>' it seems strange to throw a "failed error", that's the way I read it anyway. I can't come up with a better one right now though.
English is not native to me, but the way I read throw failed<read_error>() is that the function (that throws) failed due to a read_error. That was my intention anyway. :)
- There should be a way to iterate over all exception_info objects contained. This is useful in a case where you don't know what information was attached to the exception. Then you just want to print everything that can be translated via lexical_cast to a logfile to get the maximum information on the exception regardless.
Just to clarify: there is a single exception_info sub-object in each exception object. In the current implementation, I could implement iteration over its content, but this iteration would only get you a void * for each object stored in it. Not very useful. On the other hand, it is useful to iterate over all info_wrapper<string,T> stored in an exception info. I'll think about implementing something along these lines. This I think is the strongest argument for changing the lib to using string IDs to identify stuff stored in exception_info, instead of tag types and the info_wrapper class template.
- I don't think it's a good idea to have a tag mechanism to access each info field. It's inconvenient having to declare the tag. Of course strings can be abused.. but that's C++. I believe simple string keys are enough and very descriptive and easy to use.
I guess I was overly concerned with abusing strings, but that's because in my experience as game programmer I've seen strings abused quite often. Several people have made similar comments, I think I'm convinced.
- why not create an operator << () that automatically does the wrapping via exception_info_wrapper instead of having a wrap_string(), wrap_errno()...
Because, in the current implementation, you can stuff anything in an exception_info, not only exception_info_wrapper objects. In the example at the end of the documentation, you can see a weak_ptr<FILE> stored in the exception_info -- just because it's one of the things that is relevant to the failure.
- I don't like the dynamic_cast involved in getting the info object. It may be enough to hide it in a small inline function if (exception_info* xi = get_exception_info(&x))
Yes, I agree the dynamic_cast is ugly. I left it that way simply because I didn't want to have two ways to get to the exception_info. Note that even with get_exception_info, the documentation pretty much tells you that a dynamic_cast will work just as well. But I guess it's ugly enough to justify adding get_exception_info function. --Emil

Emil Dotchevski <emildotchevski@hotmail.com> wrote:
- I don't think it's a good idea to have a tag mechanism to access each info field. It's inconvenient having to declare the tag. Of course strings can be abused.. but that's C++. I believe simple string keys are enough and very descriptive and easy to use.
I guess I was overly concerned with abusing strings, but that's because in my experience as game programmer I've seen strings abused quite often. Several people have made similar comments, I think I'm convinced.
Personally I like tags more. Strings have to be not only declared, but also defined, otherwise one risks suble (and impossible to catch in compilation) errors like: set("fool"); get("foo1"); Now you see the problem, but if these lines are in two separate locations (as is often the case with throw ... catch) it will be much more difficult to diagnose. Futhermore, tags provide nice clue that there are some data specific to exception being passed - just like exception hierarchy does. Last but not least, forward declarations have a nice property that they can be declared in multiple locations (no need for central location) and compiler will verify that they are used uniformly. B.

From: "Bronek Kozicki" <brok@rubikon.pl> Now you see the problem, but if these lines are in two separate locations (as is often the case with throw ... catch) it will be much more difficult to diagnose. Futhermore, tags provide nice clue that there are some data specific to exception being passed - just like exception hierarchy does. Last but not least, forward declarations have a nice property that they can be declared in multiple locations (no need for central location) and compiler will verify that they are used uniformly.
The compiler cannot check that the right tag is used since information is added to the exception at runtime, so you're still vulnerable to typos. That means you would still have to either put the tags or static strings in a central header file to unify the exception handling code at the throw/catch site. _________________________________________________________________ Express yourself instantly with MSN Messenger! Download today it's FREE! http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/

Kevin Sopp wrote:
The compiler cannot check that the right tag is used since information is added to the exception at runtime, so you're still vulnerable to typos. That means you would still have to either put the tags
you only declare them; and if you used different name than declared, compiler will catch that error. You may also declare that name wherever you want (if you keep the scope), because multiple declarations are not a problem (as opposed to multiple definitions). Presumably it would be best to put them in header files where these data are used.
or static strings in a
these have to be defined.
central header file to unify the exception handling code at the throw/catch site.
God forbid! "unified" exception handling is not something that boost should enforfce its users to do. Tags bring nice decoupling with basic static type safety; strings bring just decoupling OR compiler control with reduntant declaration/definition. I implemented similar "typeless vehicle for data" some time ago and I think I'm pretty familiar with its mechanics and potential (which goes much beyond exception handling). B.

Bronek Kozicki wrote:
Kevin Sopp wrote:
The compiler cannot check that the right tag is used since information is added to the exception at runtime, so you're still vulnerable to typos. That means you would still have to either put the tags
you only declare them; and if you used different name than declared, compiler will catch that error.
No, it will not, unless I'm misunderstanding something. You either have coupling and static checking, or you have no coupling and no static checking; strings or tags make no difference. A tag is just a compile-time string.

Peter Dimov wrote:
The compiler cannot check that the right tag is used since information is added to the exception at runtime, so you're still vulnerable to typos. That means you would still have to either put the tags you only declare them; and if you used different name than declared, compiler will catch that error. No, it will not, unless I'm misunderstanding something. You either have coupling and static checking, or you have no coupling and no static checking; strings or tags make no difference. A tag is just a compile-time string.
Tag is a type name recognized by compiler; you can declare it as many times and in as many locations as you wish. Important point about tag is that you have to declare it before you use it; compiler will enforce it. On the other hand, string is a literal; there is nothing compiler could check for you. Obviously, it means that while tags come with some coupling (although minimal - there is no need for "unified system" or "central location"), strings require no coupling at all. While this might sound like an advantage, I believe that it's not - strings (used as literals) are extremely prone to programming mistakes (like all literals). Obviously, there is simple cure: replace literal with single definition eg. macro or global const variable. But this solution comes at the cost, as you suddenly need two names: one for macro (or variable) and other for actual string. You also need guarantee that the later one is unique, and compiler will not help you with this. Tags do not have this problem - there is just one name, and language provides pretty good means (namespaces, nested types etc.) to help you make that name unique. The other problem with string is that you need its definition. Simplest solution for these problems is to keep all all string definitions in a single location - but that brings strong coupling. To sum it up : strings are prone to mistakes and there is no good cure for it; on the other hand, tags bring some (rather weak) coupling and that's it. Of you want, you can introduce requirement that tag type has to be fully defined at the point of use - compiler will provide more warranties (more difficult to define mispelled tag) and coupling will be still weaker that strings used as macros or variables (no need for central location to warranty uniqneness if you have sane design). I'm have experience with similar system, my colleagues are still figthing with problems introduced by literals used as identifiers, and we have not found good way to solve them so far. Compiler provides too few checks, and infrastructure to maintain uniqueness is too complex (and centralized). B.

Bronek Kozicki wrote:
Tag is a type name recognized by compiler; you can declare it as many times and in as many locations as you wish. Important point about tag is that you have to declare it before you use it; compiler will enforce it. On the other hand, string is a literal; there is nothing compiler could check for you. Obviously, it means that while tags come with some coupling (although minimal - there is no need for "unified system" or "central location"), strings require no coupling at all.
I suspect there is something I'm missing. Let's use examples: // file1 struct tag1; set<tag1>(); // file2 struct tagl; get<tagl>(); // NULL How can the compiler know that you misspelled tag1 as tagl? It can't.

Peter Dimov wrote:
I suspect there is something I'm missing. Let's use examples:
// file1
struct tag1; set<tag1>();
// file2
struct tagl; get<tagl>(); // NULL
How can the compiler know that you misspelled tag1 as tagl? It can't.
Indeed, but you can put tag1 in a separate header file and then include it. Had you used name nested into namespace (or type) that solution would be more obvious. To force it I even proposed to require complete type, but I do not insist that it's better (it's just different). The point of using tag is that compiler CAN help you to guarantee name uniqueness and provide name check. Compiler will not help you if you do not ask for it (like in your example). But at least you CAN use it, it will provide benefits and will NOT force you to use centralized location for all tags or build complex infrastructure - simple C++ design with nested names will suffice. If you use string, compiler will NOT help at all - no name check and no uniqueness warranties, unless you have single centralized location to store all strings and/or build complex infrastructure to manage their uniqueness. B.

Bronek Kozicki wrote:
Peter Dimov wrote:
I suspect there is something I'm missing. Let's use examples:
// file1
struct tag1; set<tag1>();
// file2
struct tagl; get<tagl>(); // NULL
How can the compiler know that you misspelled tag1 as tagl? It can't.
Indeed, but you can put tag1 in a separate header file and then include it. Had you used name nested into namespace (or type) that solution would be more obvious. To force it I even proposed to require complete type, but I do not insist that it's better (it's just different). The point of using tag is that compiler CAN help you to guarantee name uniqueness and provide name check. Compiler will not help you if you do not ask for it (like in your example). But at least you CAN use it, it will provide benefits and will NOT force you to use centralized location for all tags or build complex infrastructure - simple C++ design with nested names will suffice.
If you use string, compiler will NOT help at all - no name check and no uniqueness warranties, unless you have single centralized location to store all strings and/or build complex infrastructure to manage their uniqueness.
How does your compiler help you spot duplicate tags? Most don't diagnose ODR violations, and if your tags aren't complete, there isn't even an ODR violation.

Peter Dimov wrote:
How does your compiler help you spot duplicate tags?
compiler (or actually language) provides tools to organize names in open (namespaces) or closed (nested types) hierarchies. These tools so far worked rather well, allowing users to define unique names (where sane design and source code organization are in place). Of course, if you do not want to use these tools, you do not have to. For incomplete types it's OK to redeclare tag whenever you want to use it, and it's almost no different that using literals (although slightly annoying and one has to be careful of scope). However, once you want to organize names, tags have many advantages over strings. I tried to explain these advantages in previous messages. I believe that users will want to organize tags in all but most trivial projects, as exceptions handling begs for such organization due to its distributed nature. B.

Bronek Kozicki wrote:
Peter Dimov wrote:
How does your compiler help you spot duplicate tags?
compiler (or actually language) provides tools to organize names in open (namespaces) or closed (nested types) hierarchies. These tools so far worked rather well, allowing users to define unique names (where sane design and source code organization are in place).
Of course, if you do not want to use these tools, you do not have to. For incomplete types it's OK to redeclare tag whenever you want to use it, and it's almost no different that using literals (although slightly annoying and one has to be careful of scope). However, once you want to organize names, tags have many advantages over strings. I tried to explain these advantages in previous messages. I believe that users will want to organize tags in all but most trivial projects, as exceptions handling begs for such organization due to its distributed nature.
I've been thinking about how you might organize the tags. Consider the header that defines class file_read_error: //file_read_error.h: #include "read_error.h" class tag_file_name; //string class tag_function_name; //string class file_read_error: public read_error { }; This looks like the natural place to declare the tags. But what happens if someone looks at read_error.h: //read_error.h #include "io_error.h" class read_error: public io_error { }; The problem I see here is that if you're looking at read_error.h, it is not at all clear that some read_error exceptions have file name and function name info in them. In addition, as other pointed out as well, the compiler can not help you with avoiding typos. So really, the only way you can "organize" the tag types is by specifying them in the documentation, but you can do the same with strings. It's not like I disagree with you, after all right now the proposed Boost Exception lib uses tag types. But when you think about it, the *only* difference between the tag types and string identifiers is that strings are value types and as such they can be manipulated, read from files, etc. I think that not being able to do this stuff with the exception info identifiers is a good thing, but I don't think it's a big problem. --Emil

Bronek Kozicki wrote:
Peter Dimov wrote:
How does your compiler help you spot duplicate tags?
compiler (or actually language) provides tools to organize names in open (namespaces) or closed (nested types) hierarchies. These tools so far worked rather well, allowing users to define unique names (where sane design and source code organization are in place).
You can (and should) use the same scoping mechanism with strings. Every C++ type has a string representation. Instead of class N::X, you can use "N::X" or the more natural "N.X". If you use the same "N.X" string for two distinct purposes, there will be a problem; but you can also use the same N::X type for two different purposes, and the compiler will not warn. Strings require a bit more discipline, but not much.

Peter Dimov wrote:
You can (and should) use the same scoping mechanism with strings. Every C++ type has a string representation. Instead of class N::X, you can use "N::X" or the more natural "N.X".
If you use the same "N.X" string for two distinct purposes, there will be a problem; but you can also use the same N::X type for two different purposes, and the compiler will not warn. Strings require a bit more discipline, but not much.
you are correct, but pls. note that strings provide these benefits only when used as literals, when compiler cannot be used to enforce discipline. I believe that in many larger project (where many developers are working on single sourcetree and names are referred from many files) this is often non-acceptable and some means to organize names will be needed. Devising such means for strings is (at least) troublesome, while for tags it is straightforward. Tags naturally suit to source code organization. How exactly these tags should be organized is separate issue - I think that they should not belong to exception hierarchy (nor their header files) but form separate utility (header or set of headers) providing specific pieces of information about program state. I'd also guess that such header(s) will contain other entities (helper functions or classes) specific to given piece of information about program state. B.

Bronek, As far as typos and the exception lib are concerned, the tag types have no advantage over strings. In fact they are exactly the same. If you use tag types, you can avoid typos by declaring the tag type in a header file that's included both by the code that throws, and the code that catches. If you use strings, you can do the same thing. Ultimately I think it is better to declare the tag types directly with the code that needs them, and by doing this you're exposing yourself to typos. --Emil

On 7/4/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
- I don't like the word failed as in 'throw failed<my_error>' it seems strange to throw a "failed error", that's the way I read it anyway. I can't come up with a better one right now though.
English is not native to me, but the way I read throw failed<read_error>() is that the function (that throws) failed due to a read_error. That was my intention anyway. :)
failed<read> is quite logical, it's just the failed<read_error> that's confusing. Of course, read is a bad name for a tag. Also, as soon as you're throwing, *something* failed, so saying that again doesn't seen to necessary to me. It's already being said with the throw and the _error suffix, so the failed name seems like overkill to me. What about something along the lines of throw after<read_error>(); or throw because_of<read_error>();, if you want the readability? Or perhaps throw annotated<read_error>();? Disclaimer: I haven't really been following what the template is supposed to do, so I might be way off. I'm just commenting on the readability point. ~ Scott McMurray

me22 wrote:
What about something along the lines of throw after<read_error>(); or throw because_of<read_error>();, if you want the readability? Or perhaps throw annotated<read_error>();?
boost::throw_<read_error>(); It would be clearly seen in code and understandable. Best, Oleg Abrosimov.

On 7/6/06, Oleg Abrosimov <beholder@gorodok.net> wrote:
me22 wrote:
What about something along the lines of throw after<read_error>(); or throw because_of<read_error>();, if you want the readability? Or perhaps throw annotated<read_error>();?
boost::throw_<read_error>();
It would be clearly seen in code and understandable.
+1 for boost::throw_<> (); -- 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

Oleg Abrosimov wrote:
boost::throw_<read_error>();
It would be clearly seen in code and understandable.
Would that be throw boost::throw_< ... or just boost::throw_< ... In case of the latter, how do you insert additional information at the call site, i.e. the current throw failed<...>() << some_error_info; ? Sebastian Redl

Oleg,
boost::throw_<read_error>();
It would be clearly seen in code and understandable.
Note that the current boost::failed function template does not throw an exception; it returns an unnamed temporary, which is then used in the throw-expression, like this: throw failed<foo>(); The reason is to allow exception info to be added tirectly in the throw-expression: throw failed<foo>() << info1() << info2() .... ; I completely agree that "failed" is not a good word for this, but I couldn't come up with anything better. --Emil

Emil Dotchevski wrote:
Oleg,
boost::throw_<read_error>();
It would be clearly seen in code and understandable.
Note that the current boost::failed function template does not throw an exception; it returns an unnamed temporary, which is then used in the throw-expression, like this:
throw failed<foo>();
The reason is to allow exception info to be added tirectly in the throw-expression:
throw failed<foo>() << info1() << info2() .... ;
I completely agree that "failed" is not a good word for this, but I couldn't come up with anything better.
consider one of your examples: if( count!=fread(buffer,size,count,stream.get()) || ferror(stream.get()) ) throw boost::failed<fread_error>() << boost::wrap_string<tag_function>("fread") << boost::wrap_errno() << boost::weak_ptr<FILE>(stream); } It can be rewritten as follows: if( count!=fread(buffer,size,count,stream.get()) || ferror(stream.get()) ) boost::throw_<fread_error>() << boost::wrap_string<tag_function>("fread") << boost::wrap_errno() << boost::weak_ptr<FILE>(stream); } assuming that destructor of an object returned by boost::throw_<> does the real throw job. (Yes, I know that exceptions in destructors are evil, but in this very special case it is ok IMO). The idea behind this syntax is that temporary created by boost::throw_ would be destroyed after last call to 'operator <<'. Best, Oleg Abrosimov.

Oleg Abrosimov wrote:
It can be rewritten as follows:
if( count!=fread(buffer,size,count,stream.get()) || ferror(stream.get()) ) boost::throw_<fread_error>() << boost::wrap_string<tag_function>("fread") << boost::wrap_errno() << boost::weak_ptr<FILE>(stream); }
Yes, but what happens if boost::wrap_string throws? I know you can work your way around this issue but it's going to be really hacky. --Emil

On 7/6/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
Oleg Abrosimov wrote:
It can be rewritten as follows:
if( count!=fread(buffer,size,count,stream.get()) || ferror(stream.get()) ) boost::throw_<fread_error>() << boost::wrap_string<tag_function>("fread") << boost::wrap_errno() << boost::weak_ptr<FILE>(stream); }
Yes, but what happens if boost::wrap_string throws?
Similarily: throw std::runtime_error("my error"); What happens if std::runtime_error's constructor throws? (a temporary std::string is created so the dynamic allocation could cause std::bad_alloc to be thrown) Apparently people consider this a non-issue. And so, it seems the fact that boost::wrap_string could throw is also a non-issue. Kevin Spinar

On 7/6/06, Kevin Spinar <spinarkm@gmail.com> wrote:
On 7/6/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
Oleg Abrosimov wrote:
It can be rewritten as follows:
if( count!=fread(buffer,size,count,stream.get()) || ferror(stream.get()) ) boost::throw_<fread_error>() << boost::wrap_string<tag_function>("fread") << boost::wrap_errno() << boost::weak_ptr<FILE>(stream); }
Yes, but what happens if boost::wrap_string throws?
Similarily:
throw std::runtime_error("my error");
What happens if std::runtime_error's constructor throws? (a temporary std::string is created so the dynamic allocation could cause std::bad_alloc to be thrown)
Apparently people consider this a non-issue. And so, it seems the fact that boost::wrap_string could throw is also a non-issue.
I'm sorry, i completely missed your point. If boost::wrap_string throws, then the stack unwinds and when the boost::throw_ object gets destroyed, it'll also throw, and std::terminate will be called because an exception was thrown while another exception was already being handled. Yes, that's a good point. Kevin Spinar

On 7/6/06, Kevin Spinar <spinarkm@gmail.com> wrote:
On 7/6/06, Kevin Spinar <spinarkm@gmail.com> wrote:
On 7/6/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
Oleg Abrosimov wrote:
It can be rewritten as follows:
if( count!=fread(buffer,size,count,stream.get()) || ferror(stream.get()) ) boost::throw_<fread_error>() << boost::wrap_string<tag_function>("fread") << boost::wrap_errno() << boost::weak_ptr<FILE>(stream); }
Yes, but what happens if boost::wrap_string throws?
Similarily:
throw std::runtime_error("my error");
What happens if std::runtime_error's constructor throws? (a temporary std::string is created so the dynamic allocation could cause
std::bad_alloc
to be thrown)
Apparently people consider this a non-issue. And so, it seems the fact that boost::wrap_string could throw is also a non-issue.
I'm sorry, i completely missed your point. If boost::wrap_string throws, then the stack unwinds and when the boost::throw_ object gets destroyed, it'll also throw, and std::terminate will be called because an exception was thrown while another exception was already being handled. Yes, that's a good point.
I've got a related question: Assume a multithreaded C++ program, if one thread is handling an exception while another thread starts to throw one, what would happen? terminate() will be called? Let's assume each thread has its own try/catch structure in its upper-most main routine. The reason I asked the question: Recently we moved from g++ 2.96 to 4.1. I started to notice terminate() gets called much more frequently with the new compiler than with the old one. I had the impression that the exception-related code in the gcc library for 2.96 was more like a kludge, so the new compiler may have come with a library more comforming to the C++ standard. However, this is for me practically a step backward. Thanks, Greg Kevin Spinar
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Gregory Dai wrote:
I've got a related question: Assume a multithreaded C++ program, if one thread is handling an exception while another thread starts to throw one, what would happen? terminate() will be called?
That's more suited to c.l.c++.m or perhaps the C++ standard discussion group. However, for what it's worth, the current C++ standard effectively ignores the existence of multithreading; thus pretty much everything concerning threading is implementation-defined. You might want to write a test case (Take two threads. Have one waiting for a signal. The other throws an exception. In the catch handler, signal the other thread, then wait for a signal yourself. The other thread starts running and throws an exception too. Is terminate() called? Then have the second thread catch the exception, signal the other thread, and terminate. Examine the contents of the first thread's exception, if it is still the same, or if it was overwritten by the other thread.) and bring the issue up with the GCC developers. IMO, exception handling is a execution flow issue and should thus be completely thread-local. Sebastian Redl

Emil Dotchevski wrote:
Yes, but what happens if boost::wrap_string throws?
I know you can work your way around this issue but it's going to be really hacky.
The C++ standard library contains a function that tests whether a stack unwind is in progress. Only throw from the destructor if that function returns false. The function is broken in VC6 though. It always returns false. I see different problems here. One is the hackish and completely unintuitive way << works: it does not create a temporary (we can't have more than one throw_ temp) and actually modifies its left argument. But that's a style issue. Far more important: doing this might wreak havoc with the compiler's flow analysis. Consider: int what_on_earth(earth &e) { if(...) { return 1; } if(...) { return 2; } if(...) { return 3; } // Something bad happened, but it's a runtime possibility, so no assert() but an exception. throw something_bad_happened(); } Now change to throw_: int what_on_earth(earth &e) { // ... boost::throw_<something_bad_happened>() << e; // Does the compiler realize this is unreachable, or will it emit a missing return value warning/error? } Sebastian Redl

I see different problems here. One is the hackish and completely unintuitive way << works: it does not create a temporary (we can't have more than one throw_ temp) and actually modifies its left argument. But that's a style issue.
I admit my current implementation is a bit hackish, not only that operator<< modifies its argument but in fact that argument is a const &. Obviously I implemented operator<< this way to avoid creating temps. But I should at least change the documentation to specify that operator<< has no effects and returns its argument by value.
int what_on_earth(earth &e) { // ... boost::throw_<something_bad_happened>() << e; // Does the compiler realize this is unreachable, or will it emit a missing return value warning/error? }
Ah yes, you're right it could be confused. Well, using failed<> doesn't have this problem. But I do want to come up with a better name for it! --Emil

Some people may download without replying. Also, in the US, this is a big holiday weekend. Most people are off work Mon and Tue, so they probably left early Thu or Fri as well...
participants (11)
-
Bronek Kozicki
-
Dean Michael Berris
-
Emil Dotchevski
-
Gregory Dai
-
Jody Hagins
-
Kevin Sopp
-
Kevin Spinar
-
me22
-
Oleg Abrosimov
-
Peter Dimov
-
Sebastian Redl