Fwd: [boost] Re: Exceptions as streams

On 10/02/2004, at 12:14 PM, Jonathan Turkanis wrote:
"Geoff Leyland" <gley001@ec.auckland.ac.nz> wrote in message news:9EDC4024-5B52-11D8-B48C-000A95DB9BF6@ec.auckland.ac.nz...
Hi,
Excuse me if this is already somewhere in boost - I haven't managed to find it. Does anyone else think that an exception that you can write to like a stream would be useful? ...
Have you seen
http://www.boost.org/more/error_handling.html
particularly item 4 ("Format the what() message o demand"), but also 3 and 5?
Jonathan
I have now, thanks, and in principle I agree with what it says. I think, though, that not all exceptions are created equal. When I first started using exceptions I wrote an exception class that had static buffers for the data it might need to store, because I thought that exceptions might be thrown in low memory situations. I don't think I have ever seen any of my code throw an out of memory exception. I don't think I've ever seen a string constructor throw. I know that the stream operators could probably throw, but they don't very much compared to the mistakes I make. I have also been down the road of writing loads of little exception classes for different kinds of problem, each containing the relevant fields for the particular type of exception, so that all the data you needed to interpret the exception was available in the public interface of the exception. Needless to say, it was a pain in the ass, and I never wrote any code that interpreted the data in the exception (except to format "what") In my little command line world, the errors I usually get are that people have forgotten a key-value pair in an input file, or they've spelt the path to a plugin wrong. I could print out the problem and try to continue, and inevitably crash. I could print out the problem and exit or assert, but sometimes I'm running hundreds of tests over a few days, and I don't want the damn thing to stop completely in the middle of the night because I've made a mistake configuring one of the tests. So what I do is throw an exception with a readable message. The main program running the test loop can catch these exceptions, store them all up, and print them all out right at the end of the tests, telling me which tests had problems and why, so that they don't get lost in all the other guff the tests are printing out. There are lots of legitimate reasons for throwing lots of types of exceptions, and I'm not implying that throwing some kind of "streamy_exception" is appropriate in all (or even more than a few) places, but it has made my life a lot easier, and made a lot of silly mistakes easier to fix. cheers, Geoff

"Geoff Leyland" <gley001@ec.auckland.ac.nz> wrote in message:
I think, though, that not all exceptions are created equal. When I first started using exceptions I wrote an exception class that had static buffers for the data it might need to store, because I
that exceptions might be thrown in low memory situations. I don't think I have ever seen any of my code throw an out of memory exception. I don't think I've ever seen a string constructor throw. I know
the stream operators could probably throw, but they don't very much compared to the mistakes I make.
I have also been down the road of writing loads of little exception classes for different kinds of problem, each containing the relevant fields for the particular type of exception, so that all the data you needed to interpret the exception was available in the public interface of the exception. Needless to say, it was a pain in the ass, and I never wrote any code that interpreted the data in the exception (except to format "what")
In my little command line world, the errors I usually get are that people have forgotten a key-value pair in an input file, or they've spelt the path to a plugin wrong.
I could print out the problem and try to continue, and inevitably crash.
I could print out the problem and exit or assert, but sometimes I'm running hundreds of tests over a few days, and I don't want the damn thing to stop completely in the middle of the night because I've made a mistake configuring one of the tests.
So what I do is throw an exception with a readable message. The
thought that main
program running the test loop can catch these exceptions, store them all up, and print them all out right at the end of the tests, telling me which tests had problems and why, so that they don't get lost in all the other guff the tests are printing out.
There are lots of legitimate reasons for throwing lots of types of exceptions, and I'm not implying that throwing some kind of "streamy_exception" is appropriate in all (or even more than a few) places, but it has made my life a lot easier, and made a lot of silly mistakes easier to fix.
Are you proposing a single new exception which overloads operator<<, for use in testing, or are you thinking of using it as a framework for user-define exceptions in situations where the programmer judges that low resources will not be a problem? To me, the ability to write an exception to a stream is unimportant, since you can just use what(). The ability to write to an exception class using operator<< has a certain appeal; I would defintely use if it were free. On the other hand, if the stream operations are only happening before the exception is thrown, and if you are dealing with an exception type that already has the ability to hold some text, you can get the same effect by using a stringstream. I'm not sure it's worth introducing a new exception class just to save programmers the trouble of defining a stringstream. Maybe for use in certaint types of testing it would be helpful. Also, have you looked at Boost.Test? Jonathan

On 10/02/2004, at 2:36 PM, Jonathan Turkanis wrote:
Are you proposing a single new exception which overloads operator<<, for use in testing, or are you thinking of using it as a framework for user-define exceptions in situations where the programmer judges that low resources will not be a problem?
Well, I have a use case in which it helps me, which I explained in the last post - and I can explain further if you like - and perhaps there are others. I think that for testing and correctness Boost.Test type things and and assertions are the right tools. I guess I am using it in a case: where I judge that low resources will not be a problem; where, if an another exception occurs in generating the exception, well, bummer; where it's not worth spending time on a nicer mechanism; where I would like a semi-explanatory error message to be printed on the console or saved; where I do want the option of continuing with something (the next test), but I'm not really interested in rectifying the error. In my particular case, as I said, the errors usually come from the user not getting an input file quite right (parseable, but not containing all the information I later need) On 10/02/2004, at 2:54 PM, Reece Dunn wrote:
Using a stringstream would be my approach to achieve this affect, but I wonder what would happen if the stream operation generated an exception? E.g.
throw( std::ostringstream() << "Error #" << 404 << weberror( 404 ));
I'm actually using it to replace the case where, lazy as I am, I couldn't be bothered creating a new exception class, and just threw a char *: throw "Couldn't open the file"; Which is certainly exception safe, and very mindful of limited resources, but when you're trying to open about 20 user specified files and dlls, not very informative. So throw streamy_exception() << "Couldn't open the file '" << file_name << "'"; is a world better for me. Yes, it uses lots of resources. Yes, the exception constructor and subsequent streaming could throw, but my experience has shown that the biggest danger is neither of these. What goes wrong is that I'm too lazy to write a really nice exception for every case, and so uninformative exceptions are thrown.
what if weberror thows an exception? Also, is ostringstream guaranteed not to throw an exception?
What about throw spiffy_web_exception(404, weberror(404)); It's not much different is it? You could call weberror() in the exception's what(), inside a try block, but if it did throw, what would you do? throw spiffy_web_error(404); then virtual const char *spiffy_web_error::throw(void) const throw() { static std::string temp; try { std::ostringstream os; os << "Error #" << error_number << weberror( error_number ); temp = os.str(); return temp.c_str(); } catch (...) { return "spiffy_web_error : couldn't work out what happened, sorry" } } The message in the final case doesn't give much useful information. Also, you can see in order to get a char * that will live beyond the scope of what you have to either: have something like a static temporary string-type thing lying around or strcpy os.str into some newed memory; make the ostringstream a member of the exception - and so have it constructed at the time you throw it - risking the double exception again; have a better idea? and also shows why sometimes it might, just might, be easier to go: std::cerr << s; rather than std::cerr << s.what();
Throwing an exception during the exception process is not a good idea!
It's not that bad - the program exits without giving a clear indication of what went wrong. If the alternative is to have the program exit without giving a clear indication of what went wrong, then that's probably ok. I do agree that you could throw an ostringstream though. The advantages I see of throwing an exception I see are You get to overload what(). You can extend the exception : throw streamy_web_error(404) << "Error #" << 404 << weberror( 404 ); (You could potentially disable the streamy part (make "<<" do nothing), and end up throwing an exception that spat out a readable error in a command line version, an exception containing just the error code and type information in (say) a windows version, and, to some extent, get some free documentation at the point of the error.) I'm also imagining that by using the format library and some kind of translation tool, you could probably fairly easily get translated versions of the text of your exception. I haven't played with the format library that much though. I'm certainly not advocating that everyone who uses exceptions should use such an exception. Those who can do better certainly should. Nor am I advocating that Boost libraries should throw such exceptions : I think it would be a very bad idea for Boost to put all that stream overhead into libraries that don't need it or to throw exceptions in english. However, if there are other people like me who write throw "oops. Something went wrong"; or even throw 1; in their own code, as I often did in the last days of my thesis, then maybe such a facility will help them a bit. Of course they could write such an exception themselves, but there are one or two tricks : you really do get problems if you try to return os.str.c_str() to an ostringstream in what()'s scope. cheers, Geoff

On 10/02/2004, at 2:36 PM, Jonathan Turkanis wrote:
Are you proposing a single new exception which overloads operator<<, for use in testing, or are you thinking of using it as a framework for user-define exceptions in situations where the programmer judges
low resources will not be a problem?
Well, I have a use case in which it helps me, which I explained in
last post - and I can explain further if you like - and perhaps
"Geoff Leyland" <gley001@ec.auckland.ac.nz> wrote in message news:F830594E-5B79-11D8-B48C-000A95DB9BF6@ec.auckland.ac.nz... that the there
are others.
I think that for testing and correctness Boost.Test type things and and assertions are the right tools.
I guess I am using it in a case: where I judge that low resources will not be a problem; where, if an another exception occurs in generating the exception, well, bummer; where it's not worth spending time on a nicer mechanism; where I would like a semi-explanatory error message to be printed on the console or saved; where I do want the option of continuing with something (the next test), but I'm not really interested in rectifying the error.
In my particular case, as I said, the errors usually come from the user not getting an input file quite right (parseable, but not containing all the information I later need)
I got that part. I agree that there are times when the convenience of using strings (or streams) might outweigh the other disadvantages we discussed. But I think people trying to write reusable code will be reluctant to define exceptions that are only appropriate for limited circumstances. After all, part of the justification for introducing exceptions was that code which is in a position to detect errors often does not how to handle them appropriately, and some of the conditions you mention above sound like judgement that the programmer trying to handle exceptions might be in a better to make than the programmer wri ting the code which throws the exceptions. For small programs written by one person these issues are not so important. (These are also the cases where you can get away with thowing int or const char* ;-) Best Regards, Jonathan

On 10/02/2004, at 5:00 PM, Jonathan Turkanis wrote:
I got that part. I agree that there are times when the convenience of using strings (or streams) might outweigh the other disadvantages we discussed. But I think people trying to write reusable code will be reluctant to define exceptions that are only appropriate for limited circumstances. After all, part of the justification for introducing exceptions was that code which is in a position to detect errors often does not how to handle them appropriately, and some of the conditions you mention above sound like judgement that the programmer trying to handle exceptions might be in a better to make than the programmer wri ting the code which throws the exceptions.
Yes, quite. I hope I'm not labouring a point too much here, but my experience is that what's usually wrong with error handling is that the library just exit()s when there's an error (which a lot of old fortran I've used did). It's also quite a lot of work to wrap information about an error up at the point at which it occurs, and then to extract it at some later moment and do something intelligent with it. Quite often, the "intelligent" thing that is done is to report an error to the user, and that error can quite often be reasonably well described at the point at which it happened. Throwing a streamy exception has small advantages over a const char * (you can add more information) and an ostringstream (you can catch it as a std::exception) and it lends itself to further extension. Notice that because I'm throwing an exception, *not* an ostringstream, nothing precludes one from also including information of more general interest in the exception.
For small programs written by one person these issues are not so important. (These are also the cases where you can get away with thowing int or const char* ;-)
Yes. And in cases where you might get away with an int or const char *, something nicer might make things even easier. The question is: is this what Boost is about? Perhaps Boost shouldn't be encouraging programming like this, perhaps some users of Boost are writing clunky command like computational code. cheers, Geoff

"Geoff Leyland" <gley001@ec.auckland.ac.nz> wrote in message news:D6E59621-5B82-11D8-B48C-000A95DB9BF6@ec.auckland.ac.nz...
On 10/02/2004, at 5:00 PM, Jonathan Turkanis wrote:
(you can add more information) and an ostringstream (you can catch it as a std::exception) and it lends itself to further extension.
Throwing a streamy exception has small advantages over a const char
Definitely! Throwing a const char* is always a bad idea, since no one expects to catch a const char*, and even if you write a const char* handler there's no way to tell in advance that you will be able to handle the error represented by the const char*. In general, you cannot throw a stringstream, since streams need not be copyable.
For small programs written by one person these issues are not so important. (These are also the cases where you can get away with thowing int or const char* ;-)
Yes. And in cases where you might get away with an int or const char *, something nicer might make things even easier.
The question is: is this what Boost is about? Perhaps Boost shouldn't be encouraging programming like this, perhaps some users of Boost are writing clunky command like computational code.
I think boost should encourage best practices, not practices which work acceptably only in limited circumstances without providing substantial benefits. For miscellaneous errors, you can use one the standard exception classes, such as runtime_error, using a stringstream to format the results, if you like: stringstream s; s << "somebody made " << x << " mistakes"; throw runtime_error(s.str()); This gives you the results you want, doesn't it? Is it really that inconvenient? Jonathan

On 10/02/2004, at 6:54 PM, Jonathan Turkanis wrote:
I think boost should encourage best practices, not practices which work acceptably only in limited circumstances without providing substantial benefits.
Fair call.
For miscellaneous errors, you can use one the standard exception classes, such as runtime_error, using a stringstream to format the results, if you like:
stringstream s; s << "somebody made " << x << " mistakes"; throw runtime_error(s.str());
This gives you the results you want, doesn't it? Is it really that inconvenient?
Oh, well I'm alright, because I'll go on using my streamy exception where I think it's warranted. Convenience is an interesting question though. To some extent (no offence to the authors of excellent libraries that I use a lot and am extremely grateful for) my use of boost::lambda and boost::bind amounts to avoiding the inconvenience of hand writing function objects - but I wouldn't want to live without them. Funny that gcc's runtime_error uses a string copy constructor that could potentially throw :-) cheers, Geoff

"Geoff Leyland" <gley001@ec.auckland.ac.nz> wrote in message news:E94BA576-5B96-11D8-B48C-000A95DB9BF6@ec.auckland.ac.nz...
On 10/02/2004, at 6:54 PM, Jonathan Turkanis wrote:
I think boost should encourage best practices, not practices which work acceptably only in limited circumstances without providing substantial benefits.
Fair call.
For miscellaneous errors, you can use one the standard exception classes, such as runtime_error, using a stringstream to format the results, if you like:
stringstream s; s << "somebody made " << x << " mistakes"; throw runtime_error(s.str());
This gives you the results you want, doesn't it? Is it really that inconvenient?
Oh, well I'm alright, because I'll go on using my streamy exception where I think it's warranted.
No objection here.
Convenience is an interesting question though. To some extent (no offence to the authors of excellent libraries that I use a lot and
am
extremely grateful for) my use of boost::lambda and boost::bind amounts to avoiding the inconvenience of hand writing function objects <snip>
That's what they're for. I like convenience too. ;-)
Funny that gcc's runtime_error uses a string copy constructor that could potentially throw :-)
True, using the standard exception classes does not necessarily address all the issues discussed in the guidelines. I haven't studied the libstdc++ string class in detail, but I think it's a reference counted string whose copy constructor shouldn't throw in the circumstances we've discussed. Other libraries (Dinkumware, I think) definitely have this problem. Jonathan

At Tuesday 2004-02-10 00:01, you wrote:
On 10/02/2004, at 6:54 PM, Jonathan Turkanis wrote:
I think boost should encourage best practices, not practices which work acceptably only in limited circumstances without providing substantial benefits.
Fair call.
For miscellaneous errors, you can use one the standard exception classes, such as runtime_error, using a stringstream to format the results, if you like:
stringstream s; s << "somebody made " << x << " mistakes"; throw runtime_error(s.str());
This gives you the results you want, doesn't it? Is it really that inconvenient?
Oh, well I'm alright, because I'll go on using my streamy exception where I think it's warranted.
Convenience is an interesting question though. To some extent (no offence to the authors of excellent libraries that I use a lot and am extremely grateful for) my use of boost::lambda and boost::bind amounts to avoiding the inconvenience of hand writing function objects - but I wouldn't want to live without them.
Funny that gcc's runtime_error uses a string copy constructor that could potentially throw :-)
what exception do you see it throwing (possibly) ?
cheers, Geoff
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Victor A. Wagner Jr. http://rudbek.com The five most dangerous words in the English language: "There oughta be a law"

On 11/02/2004, at 4:48 AM, Victor A. Wagner, Jr. wrote:
At Tuesday 2004-02-10 00:01, you wrote:
Funny that gcc's runtime_error uses a string copy constructor that could potentially throw :-)
what exception do you see it throwing (possibly) ?
Well, I thought it might throw a bad_alloc and, as Jonathan said :
Have you seen
http://www.boost.org/more/error_handling.html
particularly item 4 ("Format the what() message o demand"), but also 3 and 5?
See item 3. However, Jonathan also cleared up the bad_alloc:
...I haven't studied the libstdc++ string class in detail, but I think it's a reference counted string whose copy constructor shouldn't throw in the circumstances we've discussed. Other libraries (Dinkumware, I think) definitely have this problem.
I haven't looked past the stdexcept header in gcc, but at a brief glance it seems to me that MSL's runtime_exception could throw a bad_alloc. cheers, Geoff

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Geoff Leyland Sent: 10 February 2004 00:14 To: Boost mailing list Subject: Fwd: [boost] Re: Exceptions as streams | I could print out the problem and exit or assert, but sometimes I'm | running hundreds of tests over a few days, and I don't want the damn | thing to stop completely in the middle of the night because I've made a | mistake configuring one of the tests.
From what you say, using Boost Test is most definitely what you need.
It does exactly what you want - though it does take some setting up, which you will balk at. But I feel sure from my experience that it will be worth it. Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK +44 01539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com

On 11/02/2004, at 3:26 AM, Boost wrote:
| I could print out the problem and exit or assert, but sometimes I'm | running hundreds of tests over a few days, and I don't want the damn | thing to stop completely in the middle of the night because I've made a | mistake configuring one of the tests.
From what you say, using Boost Test is most definitely what you need.
It does exactly what you want - though it does take some setting up, which you will balk at.
Sorry, read "simulations" (in as in simulating a physical system) rather than "tests" - there could be some confusion there. Although I don't claim to be an expert in Boost.Test, I haven't balked at the setting up it takes in the cases where I (perhaps unimaginatively) thought it fitted. Are you suggesting I should have a longer look at program_execution_monitor? Does have a way of saving up the errors that occur (and stop individual simulations) during a run and then print me all the details (with test names) at the end (will it mail them to me as they happen? That'd be great.) cheers Geoff
participants (4)
-
Boost
-
Geoff Leyland
-
Jonathan Turkanis
-
Victor A. Wagner, Jr.