Exception lib proposal update: what()

Hello, I just finished an update to the exception library I am planning to propose for addition to Boost. I appreciate all feedback, including incompatibility reports with various compilers (I believe the implementation to be standard-conforming, but I have only tested with msvc 7.1/8.0 and gcc 3.4.4). As usual, the latest documentation is here: http://www.revergestudios.com/boost-exception/boost-exception.htm Here is a zip file with the source code, complete with jamfiles and tests: http://www.revergestudios.com/boost-exception/boost-exception.zip Here's what's new in this update: class boost::exception now defines what() function, similarly to std::exception. It automatically formats a message which combines all exception info stored by operator<< in the boost::exception object. The message is not user-friendly; it is designed for dumping in log files and for other debugging systems. For what() to work, the system needs to be able to convert the exception info values stored in a boost::exception to string. Because this is not a critical feature, I thought it wouldn't be a good idea to require the user code to provide such a conversion for everything. The current implementation generates a string representation of each exception info value (at the time exception_info is called) as follows: - If a suitable overload for the unqualified call to to_string (passing the exception info value as the only argument) is found, that overload is used. - Otherwise, if a suitable overload for serializing the exception info value into a std::ostringstream is found, that overload is used. - Otherwise the system gives up and uses a generic "stub" string to indicate that the exception info value could not be converted to string. This is accomplished through the to_string function template, which has the following signature: template <class T> std::string to_string( T const &, char const * stub ); Do you think that to_string is universally useful? Is there anything in Boost with similar functionality? Perhaps we can make to_string a separate addition to Boost? Thanks, Emil

Emil Dotchevski wrote:
Hello,
I just finished an update to the exception library I am planning to propose for addition to Boost. I appreciate all feedback, including incompatibility reports with various compilers (I believe the implementation to be standard-conforming, but I have only tested with msvc 7.1/8.0 and gcc 3.4.4).
[...] I am not a exception expert, but I am just wondering, why the exception library does not support UNICODE. Is there any technical restriction? If a exception library support UNICODE as , we can throw user friendly message.

gchen opined:
Emil Dotchevski wrote:
Hello,
I just finished an update to the exception library I am planning to propose for addition to Boost. I appreciate all feedback, including incompatibility reports with various compilers (I believe the implementation to be standard-conforming, but I have only tested with msvc 7.1/8.0 and gcc 3.4.4).
[...]
I am not a exception expert, but I am just wondering, why the exception library does not support UNICODE. Is there any technical restriction?
If a exception library support UNICODE as , we can throw user friendly message.
I think this is the wrong way to go, especially in a multi-lingual world. You should throw an error code (and some additional) information, and create an error message to display to the user at a higher level. This means that your low-level code (which could be throwing the exception) doesn't need to know the details of displaying the error message (in an alert on the screen, or written to a log file, or sent to a pager, or ?) nor the language in which the error message will be displayed in (English, German, Italian, Uzbeki, ?? ). [ Note that this is not a rejection of Unicode, but rather a separation of the error being detected and thrown and the creation of an error message ] Just my 2p. -- -- Marshall Marshall Clow Idio Software <mailto:marshall@idio.com> It is by caffeine alone I set my mind in motion. It is by the beans of Java that thoughts acquire speed, the hands acquire shaking, the shaking becomes a warning. It is by caffeine alone I set my mind in motion.

[ Note that this is not a rejection of Unicode, but rather a separation of the error being detected and thrown and the creation of an error message ]
Absolutely agree with this but one use case for unicode is attaching the possibly unicode filename of a failing file operation. Martin -- No virus found in this outgoing message. Checked by AVG Free Edition. Version: 7.1.405 / Virus Database: 268.11.5/425 - Release Date: 22/08/2006

At 10:32 PM +1000 8/23/06, Martin Slater wrote: I wrote:
[ Note that this is not a rejection of Unicode, but rather a separation of the error being detected and thrown and the creation of an error message ]
Absolutely agree with this but one use case for unicode is attaching the possibly unicode filename of a failing file operation.
Yes, that's a good case. But, you've already got some object/data structure that describes the file, right? [ A path, or something ] Attach _that_ to the exception, and Bob's your uncle. Personally, I think that the ".what ()" field in the exception is an anachronism. No one is going to show that string to end users. -- -- Marshall Marshall Clow Idio Software <mailto:marshall@idio.com> It is by caffeine alone I set my mind in motion. It is by the beans of Java that thoughts acquire speed, the hands acquire shaking, the shaking becomes a warning. It is by caffeine alone I set my mind in motion.

Marshall Clow wrote:
Yes, that's a good case. But, you've already got some object/data structure that describes the file, right? [ A path, or something ]
Attach _that_ to the exception, and Bob's your uncle.
And Fanny's your aunt;) Ah of course, all too easy then. thanks for clearing that up.
Personally, I think that the ".what ()" field in the exception is an anachronism. No one is going to show that string to end users.
I suspect quite a few people do and many won't admit it, I know I do in one particular app but there as in many programs the user base is limited and well known. For any app that needs to be internationalised or have more than a simple interface though I agree that this is completely insufficent, (and hence this library interesting). cheers Martin -- No virus found in this outgoing message. Checked by AVG Free Edition. Version: 7.1.405 / Virus Database: 268.11.5/425 - Release Date: 22/08/2006

On Wed, Aug 23, 2006 at 07:53:12AM -0700, Marshall Clow wrote:
No one is going to show that string to end users.
Hmmm, I do, quite frequently actually. Maybe I'm just anachronistic, but I do hold useful error messages in high value. :-) Regards -Gerhard -- Gerhard Wesp ZRH office voice: +41 (0)44 668 1878 ZRH office fax: +41 (0)44 668 1818 For the rest I claim that raw pointers must be abolished.

Gerhard Wesp wrote:
On Wed, Aug 23, 2006 at 07:53:12AM -0700, Marshall Clow wrote:
No one is going to show that string to end users.
Hmmm, I do, quite frequently actually. Maybe I'm just anachronistic, but I do hold useful error messages in high value. :-)
I'm pretty sure there is a confusion here :) The discussion (I hope) is about the exception lib that I'm proposing for addition to boost, and the what() function of class boost::exception. You're probably thinking about std::exception::what(), which is different. I realize naming the function what() is begging for this confusion, but I named it what() because its purpose is very similar: to identify the exception (info stored in the exception) object, not to format a message for the user. --Emil Dotchevski

On Wed, Aug 23, 2006 at 10:39:35AM -0700, Emil Dotchevski wrote:
addition to boost, and the what() function of class boost::exception. You're probably thinking about std::exception::what(), which is different.
I see. Indeed I was confusing the two.
named it what() because its purpose is very similar: to identify the exception (info stored in the exception) object, not to format a message for the user.
Still, I *do* use the what() string in std::exception to format a message for the user, and this turns out to work pretty well. AFAIK, the standard doesn't assign a purpose to the what() string---It is what it is, a string held by the exception object. Regards -Gerhard -- Gerhard Wesp ZRH office voice: +41 (0)44 668 1878 ZRH office fax: +41 (0)44 668 1818 For the rest I claim that raw pointers must be abolished.

Gerhard Wesp wrote:
On Wed, Aug 23, 2006 at 10:39:35AM -0700, Emil Dotchevski wrote:
addition to boost, and the what() function of class boost::exception. You're probably thinking about std::exception::what(), which is different.
I see. Indeed I was confusing the two.
named it what() because its purpose is very similar: to identify the exception (info stored in the exception) object, not to format a message for the user.
Still, I *do* use the what() string in std::exception to format a message for the user, and this turns out to work pretty well. AFAIK, the standard doesn't assign a purpose to the what() string---It is what it is, a string held by the exception object.
If I understand you correctly, you are storing a user message in the exception when you throw it, and then use std::exception::what() to retrieve it, right? This approach is problematic for several reasons, most notably because the user message has to be localized, but also because different programs may need to output different messages in response to the same exception thrown by a shared library. The job of the exception object is not to format a user message, but to deliver enough information to the catch site so that it can format a user message. About std::exception::what(), until recently I was implementing it in my base exception class as "return typeid(*this).name()". Since I converted all of my code to use the proposed boost exception library, my base exception class derives virtually from std::exception and virtually from boost::exception, and is implemented as "return boost::exception::what()". I am playing with the idea to add the typeid(*this).name() as part of the non-user-friendly string formatted by boost::exception::what(). --Emil Dotchevski

On Wed, Aug 23, 2006 at 11:20:20AM -0700, Emil Dotchevski wrote:
If I understand you correctly, you are storing a user message in the exception when you throw it, and then use std::exception::what() to retrieve it, right? This approach is problematic for several reasons, most notably
Indeed. I don't localize error messages, in fact I've never met a program that correctly and completely implemented localized error messages. I guess it's because the problem doesn't scale so well.
because the user message has to be localized, but also because different programs may need to output different messages in response to the same exception thrown by a shared library.
Hmmm... Can you give an example? I try to restrict the what() string to be indepentent of library usage and add more information higher up the call stack, possibly re-throwing afterwards. E.g., a file object constructor might throw "couldn't open <filename>: <error>" and then, it's caller might prepend some more context information to make that either "Reading configuration file: couldn't open <filename>: <error>" or "Parsing data file: couldn't open <filename>: <error>" This works quite well, but yeah, maybe there are situations where string concatenation is too simplistic. Regards -Gerhard

In article <20060824085903.GF9119@google.com>, Gerhard Wesp <gwesp@google.com> wrote:
On Wed, Aug 23, 2006 at 11:20:20AM -0700, Emil Dotchevski wrote:
If I understand you correctly, you are storing a user message in the exception when you throw it, and then use std::exception::what() to retrieve it, right? This approach is problematic for several reasons, most notably
Indeed. I don't localize error messages, in fact I've never met a program that correctly and completely implemented localized error messages. I guess it's because the problem doesn't scale so well.
It doesn't really matter if a program correctly and completely implements localized error messages -- even if you only get the most common error messages translated into the most languages most commonly used among your users, you will make a huge difference in their ability to understand what your program is trying to tell them. Inability to solve the entire problem is not an excuse to try solving important parts of it. The problem of localizing error messages is not fundamentally harder than producing useful error messages in English. If you can do English well (and I do not consider "Parsing data file: couldn't open <filename>: <error>" to be a good error message in English), you probably have enough machinery in the code to do most other languages well, and localization becomes a simple matter of hiring translators. For example, the app that I work on will give you error messages such as "The file 'XYZZY' could not be transferred because you do not have the required permissions on the server." -- and that still leaves a lot of room for improvement. Importantly, though, once we built the ability to construct meaningful English sentences using information from high levels of the app (where the user action is know) and low levels of the app (where the precise failure is known), also doing so in the six other languages that we support was trivial.
because the user message has to be localized, but also because different programs may need to output different messages in response to the same exception thrown by a shared library.
Hmmm... Can you give an example? I try to restrict the what() string to be indepentent of library usage and add more information higher up the call stack, possibly re-throwing afterwards. E.g., a file object constructor might throw "couldn't open <filename>: <error>" and then, it's caller might prepend some more context information to make that either "Reading configuration file: couldn't open <filename>: <error>" or "Parsing data file: couldn't open <filename>: <error>"
This works quite well, but yeah, maybe there are situations where string concatenation is too simplistic.
Any time you attempt to address your users in a language that they use in everyday life, as opposed to the geek language that makes the programmers' lives easier, string concatenation is way too simplistic. Error information returned by a well-designed API carries enough semantic content for the clients of that API to use in their own representation of the errors -- different clients have different error reporting needs. As a result, there is nothing inherently wrong with using strings for identifying errors, as long as the exact values of those strings are documented as part of the API, and are maintained as any other part of the API (e.g., if you want to change one of them, you have to consider backward compatibility). Basically, if an API treats error strings returned as it would treat error codes returned, then there is no problem; on the other hand, if an API treats error strings as private values that clients cannot rely on, then the clients have their hands tied. (As an aside, part of what makes user-friendly error reporting difficult is the fact that many APIs have poorly defined error semantics in the first place.) Ben -- I changed my name: <http://periodic-kingdom.org/People/NameChange.php>

Marshall Clow wrote:
At 10:32 PM +1000 8/23/06, Martin Slater wrote: I wrote:
[ Note that this is not a rejection of Unicode, but rather a separation of the error being detected and thrown and the creation of an error message ]
Absolutely agree with this but one use case for unicode is attaching the possibly unicode filename of a failing file operation.
Yes, that's a good case. But, you've already got some object/data structure that describes the file, right? [ A path, or something ]
Attach _that_ to the exception, and Bob's your uncle.
I'm not sure if uncle Bob realizes that attaching the file object to the exception would require that the file object is copyable, and usually they aren't (unless refcounted), and that this would keep the file open until the exception is processed (which is not desirable). Check out http://www.revergestudios.com/boost-exception/boost-exception.htm#example to see how file errors can be handled with the exception lib.
Personally, I think that the ".what ()" field in the exception is an anachronism. No one is going to show that string to end users.
Like I said in my original post, what() is just for debugging/logging purposes. --Emil

On 8/21/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
Hello,
I just finished an update to the exception library I am planning to propose for addition to Boost. I appreciate all feedback, including incompatibility reports with various compilers (I believe the implementation to be standard-conforming, but I have only tested with msvc 7.1/8.0 and gcc 3.4.4).
As usual, the latest documentation is here:
http://www.revergestudios.com/boost-exception/boost-exception.htm
Here is a zip file with the source code, complete with jamfiles and tests:
http://www.revergestudios.com/boost-exception/boost-exception.zip
Here's what's new in this update: class boost::exception now defines what() function, similarly to std::exception. It automatically formats a message which combines all exception info stored by operator<< in the boost::exception object. The message is not user-friendly; it is designed for dumping in log files and for other debugging systems.
For what() to work, the system needs to be able to convert the exception info values stored in a boost::exception to string. Because this is not a critical feature, I thought it wouldn't be a good idea to require the user code to provide such a conversion for everything. The current implementation generates a string representation of each exception info value (at the time exception_info is called) as follows:
- If a suitable overload for the unqualified call to to_string (passing the exception info value as the only argument) is found, that overload is used.
- Otherwise, if a suitable overload for serializing the exception info value into a std::ostringstream is found, that overload is used.
- Otherwise the system gives up and uses a generic "stub" string to indicate that the exception info value could not be converted to string.
This is accomplished through the to_string function template, which has the following signature:
template <class T> std::string to_string( T const &, char const * stub );
Do you think that to_string is universally useful? Is there anything in Boost with similar functionality? Perhaps we can make to_string a separate addition to Boost?
std::string s = boost::lexical_cast<std::string>(T const&); Thanks,
Emil
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Thanks, Greg

"Gregory Dai" <gregory.dai@gmail.com> writes: <snip an entire quoted posting>
std::string s = boost::lexical_cast<std::string>(T const&);
http://www.boost.org/more/discussion_policy.htm#effective -- Dave Abrahams Boost Consulting www.boost-consulting.com

Gregory Dai wrote: [snip]
As usual, the latest documentation is here:
http://www.revergestudios.com/boost-exception/boost-exception.htm
Here is a zip file with the source code, complete with jamfiles and tests:
http://www.revergestudios.com/boost-exception/boost-exception.zip [snip] The current implementation generates a string representation of each exception info value (at the time exception_info is called) as follows:
- If a suitable overload for the unqualified call to to_string (passing the exception info value as the only argument) is found, that overload is used.
- Otherwise, if a suitable overload for serializing the exception info value into a std::ostringstream is found, that overload is used.
- Otherwise the system gives up and uses a generic "stub" string to indicate that the exception info value could not be converted to string.
This is accomplished through the to_string function template, which has the following signature:
template <class T> std::string to_string( T const &, char const * stub );
Do you think that to_string is universally useful? Is there anything in Boost with similar functionality? Perhaps we can make to_string a separate addition to Boost?
std::string s = boost::lexical_cast<std::string>(T const&);
This will not work because it requires that a conversion from T to std::string is available. The main use of the exception library is for storing values in exception objects, both at the time of the throw, and after a catch and before a re-throw. Purely for logging/debugging purposes, the exception lib can automatically generate a string that represents all values stored in an exception object, but it isn't reasonable to require that a conversion to string is defined for each type users can store in exception objects. The way the exception lib defines to_string, it will do what boost::lexical_cast does if such conversion is available; if the type can not be converted to string, this does not result in compile error, and a "stub" string representation is used instead (the definition of to_string is in to_string.hpp in the linked .ZIP file above.) So let me change my original question about to_string being useful by itself: isn't it a good idea to include in Boost something like to_string (or some form of lexical_cast<std::string>) that does not result in a compile error in the case when the conversion is not possible? --Emil
participants (8)
-
Ben Artin
-
David Abrahams
-
Emil Dotchevski
-
gchen
-
Gerhard Wesp
-
Gregory Dai
-
Marshall Clow
-
Martin Slater