Re: [boost] program options (consider using BOOST_THROW_EXCEPTION)

On 22 June 2012 17:51, Vladimir Prus <ghost@cs.msu.su> wrote:
On 22.06.2012 11:33, Emil Dotchevski wrote:
On Thu, Jun 21, 2012 at 11:44 PM, Vladimir Prus<ghost@cs.msu.su> wrote:
On 20.06.2012 07:44, Rowan James wrote:
On a related note; is there interest in a patch set to use
BOOST_THROW_EXCEPTION to add this (yes, programmer-oriented) information to the exceptions thrown by Program Options and/or other Boost libraries?
Sorry, but I kinda miss context here (and I did read your original post). What are advantages of using BOOST_THROW_EXCEPTION and what are drawbacks? Could you summarize those for me?
Allow me :-
BOOST_THROW_EXCEPTION, being a macro, is able to record the file name, the function name, and the line number of the throw, which is useful when diagnosing unexpected exceptions:
catch(...) { std::cerr<< "Unexpected exception caught. Diagnostic information follows.\n"; std::cerr<< boost::current_exception_**diagnostic_information(); }
The exception object is examined dynamically for any and all useful information: type, what(), throw location, any stored boost::error_info objects, etc. The location of the throw (if available) is formatted in a way Visual Studio understands: double-clicking shows the throw location, similarly to double-clicking compile errors.
The downside is that when templates are involved, BOOST_CURRENT_FUNCTION (invoked by BOOST_THROW_EXCEPTION) can bloat the code. There is a Trac ticket for this.
Emil,
thanks for explaining. Given the above, I am not sure I am interested in using BOOST_THROW_EXCEPTION for program_options, given that exceptions are used there to report user mistakes mostly, and so function name or file line is of limited interest.
Thanks, Volodya
Thanks Emil.
If I can make the case in favour of BOOST_THROW_EXCEPTION, it is for the very reason that they are reporting user mistakes. The throw location for an exception is typically accompanied by, or at least close to, the logic that delineates such a user mistake from acceptable input. As such, it is a useful remedy in itself; but also gives the user specific information for finding documentation relevant to fixing the error. Without it, we have at best the entry point into the library that; and often a lot less if the exceptions are caught at a higher level.
Documentation for valid inputs or states to a function can only say so much about all the possible errors or exceptions that may occur.
To elaborate on what Volodya said, program_options is unusual (for Boost) library in its use of exceptions: Most of the time, exceptions are there to inform the programmer of an error in the programme. However, the majority of exceptions in program_options are there to indicate a problem in the construction of the command line by the *end-user* (not the programmer). In other words, the program *is* working exactly as designed. The programmer has no interest in the provenance of these exceptions *except* that they can be used to inform the end-user how they should retype the command line and try again. So, for example, ten times a day, I will type something like ls --colour * and ls will tell me ls: unrecognized option '--colour' and I will know to retype the US spelling... ls --color * If "ls" were using program options, an unrecognised option exception message will be thrown which eventually allows this informative message to be displayed before exiting. It is entirely unhelpful for the end-user to have Exception XXX on line xxx of file yyy.... To make it easier to use program options *in English*, the exception messages have been recently rewritten to be maximally informative to the end-user rather than the programmers. Thus we can take e.what() and write it out to std::cerr without further ado. Of course, for localisation, these error messages have to be reconstructed in the appropriate language. Hopefully, there is enough data in each exception to allow this. Curiously, the current design of exceptions in program_options ended up try to mirror what Emil has done in BOOST_THROW_EXCEPTION. When the exception is thrown deep in the bowels of the command line parsing, it does not have the full context which would allow an informative message to be constructed. The exception has to be propagated up, and then "decorated" before being rethrown. The alternative was to pass the full context down the function call hierarchy to each point at which exceptions can be thrown. This made the code horribly convoluted and ugly, and provoked loud cries of anguish from Volodya. Leo

Leo Goodstadt on 27 June 2012 12:46 wrote :
It is entirely unhelpful for the end-user to have Exception XXX on line xxx of file yyy....
Agree totally - but this is up to the application to decide what to present to the user - the point is that this information can be very useful to the developer of the application and with appropriate log files / application state dumps makes handling user reported errors much easier to recreate and fix.
To make it easier to use program options *in English*, the exception messages have been recently rewritten to be maximally informative to the end-user rather than the >programmers. Thus we can take e.what() and write it out to std::cerr without further ado. Of course, for localisation, these error messages have to be reconstructed in the appropriate language. Hopefully, there is enough data in each exception to allow this.
Whilst sensible error information is always a plus I'm not sure that you as a library writer are in any position to determine what is "maximally informative to the end-user" - that’s my job when writing the application when I've got some idea about the prospective user community.
Curiously, the current design of exceptions in program_options ended up try to mirror what Emil has done in BOOST_THROW_EXCEPTION. When the exception is thrown deep in the >bowels of the command line parsing, it does not have the full context which would allow an informative message to be constructed. The exception has to be propagated up, and then "decorated" before being rethrown.
More than curious I'd say - I imagine that you explored just using it first - were there substantive reasons not to use it? Are there possible enhancements to boost.exception which could make it useable by your library in the future? Alex

On 27 June 2012 21:46, Leo Goodstadt <leo.goodstadt@llew.org.uk> wrote:
To elaborate on what Volodya said, program_options is unusual (for Boost) library in its use of exceptions:
Most of the time, exceptions are there to inform the programmer of an error in the programme.
However, the majority of exceptions in program_options are there to indicate a problem in the construction of the command line by the *end-user* (not the programmer). In other words, the program *is* working exactly as designed. The programmer has no interest in the provenance of these exceptions *except* that they can be used to inform the end-user how they should retype the command line and try again.
It is entirely unhelpful for the end-user to have
Exception XXX on line xxx of file yyy....
I don't understand BOOST_THROW_EXCEPTION( ) to replace the output of .what() - but to supplement the output of boost::diagnostic_information( ), which I'm advocating for when the program is being tested by the development team. The diagnostics in my situation wouldn't be end-user visible. To make it easier to use program options *in English*, the exception
messages have been recently rewritten to be maximally informative to the end-user rather than the programmers. Thus we can take e.what() and write it out to std::cerr without further ado. Of course, for localisation, these error messages have to be reconstructed in the appropriate language. Hopefully, there is enough data in each exception to allow this.
The English messages are indeed an excellent touch, but I've noticed that error messages are one of the first things to be localised in a newly international product (I assume that they tend to be of a standard format which is easy for non-native speakers to implement). To handle multilingual output where specific exceptions are available is another instance where I'm going to want to look at the throw site to see how specific to the given case the exception types I'm catching actually are. Curiously, the current design of exceptions in program_options ended
up try to mirror what Emil has done in BOOST_THROW_EXCEPTION. When the exception is thrown deep in the bowels of the command line parsing, it does not have the full context which would allow an informative message to be constructed. The exception has to be propagated up, and then "decorated" before being rethrown.
I haven't worked with program_options code in a long while, so I'm unfortunately unfamiliar with the decorated info you're referring to - but it sounds similar in nature to the boost::error_info operators provided by boost::exception. The alternative was to pass the full context down the function call
hierarchy to each point at which exceptions can be thrown. This made the code horribly convoluted and ugly, and provoked loud cries of anguish from Volodya.
I understand the anguish, indeed; and I'm certainly not looking to cause more. Comparing exception strategies makes my head hurt at the best of times, and I don't presume to know what fits best with a library used by so many disparate projects.

On Wed, Jun 27, 2012 at 4:46 AM, Leo Goodstadt <leo.goodstadt@llew.org.uk>wrote:
However, the majority of exceptions in program_options are there to indicate a problem in the construction of the command line by the *end-user* (not the programmer). In other words, the program *is* working exactly as designed.
Unless it's buggy. The
programmer has no interest in the provenance of these exceptions *except* that they can be used to inform the end-user how they should retype the command line and try again.
The use case is this: int main( int argc, char const * argv[] ) { try { do_work(parse_command_line(argc,argv)); } catch( X & ) { } catch( Y & ) { } catch(...) { std::cerr << boost::current_exception_diagnostic_information(); abort(); } } The catch(...) shouldn't be reached. The BOOST_THROW_EXCEPTION information could help if it is (of course the message is intended for the programmer, not the end user.) Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

On 06/27/2012 04:51 PM, Emil Dotchevski wrote:
On Wed, Jun 27, 2012 at 4:46 AM, Leo Goodstadt<leo.goodstadt@llew.org.uk>wrote:
However, the majority of exceptions in program_options are there to indicate a problem in the construction of the command line by the *end-user* (not the programmer). In other words, the program *is* working exactly as designed.
Unless it's buggy.
The
programmer has no interest in the provenance of these exceptions *except* that they can be used to inform the end-user how they should retype the command line and try again.
The use case is this:
int main( int argc, char const * argv[] ) { try { do_work(parse_command_line(argc,argv)); } catch( X& ) { } catch( Y& ) { } catch(...) { std::cerr<< boost::current_exception_diagnostic_information(); abort(); } }
The catch(...) shouldn't be reached. The BOOST_THROW_EXCEPTION information could help if it is (of course the message is intended for the programmer, not the end user.) Hi, when I first asked about this I wasn't comprehending the nature of it being exceptions for the user but that makes complete sense. So from your advice I'm planning to tee off the information to a DEBUG level logger for the developer (untested): catch( boost::program_options::unknown_option & e ) { std::cout << "Command line incorrect: unknown option "<<e.get_option_name(); std::cout.flush(); std::cout << "\n" << desc << "\n"; LOG4CPLUS_DEBUG(logger, boost::diagnostic_information(e)); }
This way a user sees the friendlier message yet if there is some sleuthing to do, a developer or remote user may configure the runtime log level and get the more detailed information that way
Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
_______________________________________________ Unsubscribe& other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (5)
-
Alex Perry
-
Emil Dotchevski
-
Leo Goodstadt
-
Roger Martin
-
Rowan James