[boost] Re: exception context
(long post) After some thought, I'll broaden my response by (kind of) developing an exception use strategy that gives me what I want and addresses (a little) the "user messages vs debugging" question. Let's start with a "use-case" model of a system (system might be an application, server, library - whatever). As background let's say the use-case model describes the system by describing how it meets a set of goals. Each use-case shows how the system attempts to meet one goal. Each use-case describes "success" scenarios (where the goal is met) and "failure" scenarios (where the goal is not met). The failure scenarios state what the system does au lieu of meeting the goal. Ideally, we would enumerate all possible failure scenarios and say how the system behaves. Sometimes we might let the system try another strategy to meet the goal, other times we might give up (i.e. system tells user it can't meet the goal). Let's call these enumared scenarios "specific" failure scenarios. In practice it's usually not feasible to enumerate all the cases, so we have a catch-all "other" failure scenario (with some if not all use cases). How does the system handle an "other" failure scenario? Theoretically, the system should do nothing more than involve a person (this is because the system shouldn't make any assumptions about the cause of the failure, hence the state of the system, because the state could be anything). Let's call "involving a person" post-mortem debugging. The first person to get involved might be a user (who has application domain knowledge but little else), followed by a support person (who has application environment and behaviour knowledge but not internals knowledge), and lastly a developer (who has internals knowledge). (In practice, some or all of these people might be missing from the chain or there might be more, but let's just assume these three for now). To do post-mortem, the system must provide lots of information: what was the reason for the failure, what was the context of the failure, what happened before the failure. Different subsets of the information will be useful depending on the person (our user only knows about domain concepts, while the developer knows about internal concepts). So to be useful to all, we need to capture all these levels of information. How might we capture it? A core dump is typically very good for the developer, but not so good for the user. A stack trace might be slightly better for the user, but not so good for the developer (it will typically omit parameter values and object states). Neither of these are acceptable in all environments. "trace" messages might be somewhat useful to the developer and perhaps useful for the user: they at least show some history (except when they're turned off :-). Again they're not acceptable in all environments. A strategy that I've seen work very well is to map failure scenarios to (C++) exceptions, and collect context information as these exceptions propogate up the call chain. The context information collected being function descriptions augmented with parameter values (including *this state for methods) and file-and-line references (i.e. references back to the source code). The software can then use whatever is appropriate to get the information to the people (in some environments it might not even bother). How to map this to C++? Create a class to represent "other" failure scenarios that can collect context. e.g. class Exception { public: Exception(string failureReason) throw(); string getFailureReason() throw(); void addContext(string context) throw(); vector getContext() const throw(); }; (We'll come back to this class' limitations below.) Put each function's implementation in a try/catch block that adds context. e.g. void Doc::save(string fileName) throw(Exception) { try { ... implementation details, particularly calling ... functions that only throw Exception or derived } catch(Exception& e) { e.addContext("save document " + title_ + " to file " + fileName); throw; } } In main() (or elsewhere if you want to gamble and try to recover), catch Exception and form an error message like: Failed to *(e.getContext().end()-1) because failed to *(e.getContext().end()-2) because : failed to *(e.getContext().begin()) because e.getCause(). (Notice that for what I'd call a well designed system, the top lines of the message will generally mention domain terms. These will gradually give way to "internals" terms as we go down. So our user might be able to post-mortem debug using the top few lines (and the failure reason) while the support and developer will probably be more interested in the last parts of the message.) For each "specific" failure scenario, use a separate C++ exception class that carries all the information needed to take action programmatically. For robustnes
[boost] Re: exception context
Hello everyone, A quick note to let you know I hadn't forgotten about my post... I finally got some time to get back to this - thanks to Russell, Alisdair, Thomas, Darren, Greg, Brian, Gennaro for your replies. At the moment I'm still trying to digest all the info posted (including the reference to the "call stack library" thread that I went and found and read - thanks Russell, it was called "improved exceptions", around July 2002). I'm still hoping to tie all the info together and somehow reason a way forward... ... but I might fail to do that and just throw my ideas in as well :-) Look out for something soon. Trevor ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: exception context
"Darren Cook" <[EMAIL PROTECTED]> wrote in message news:[EMAIL PROTECTED] [snip] > I wanted something like the call stack that shows in python or java when an > uncaught exception occurs; I tried to start a discussion on something similar, although I wanted language support. However, one of my points also were (and is) that it would be nice not only for uncaught exceptions, but also for running programs. My concern is that we have no standard mechanism for inspecting the errors in running programs when they (perhaps) have shipped to the customer. What is particularly irritating is that one instance of a program might work "perfect" whereas another instance may contain errors. If we cannot inspect those errors, we're in trouple if we cannot redo these errors . The entire thread can be found here: http://groups.google.com/groups?hl=da&lr=&ie=UTF-8&selm=b1g8ca%2497i%241%40s unsite.dk regards Thorsten ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: exception context
Thanks, I've learnt some history of C++ :-) The dates in your document also allowed me to locate a relevant WP. For those interested: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/wp/pdf/jan94/body.pdf As it appears, the specification of the standard exception classes underwent major changes in that year and only began to look like we know it now in January of the year after (Jan 95 working paper). Genny. ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: exception context
EXCEPT.DOC Description: MS-Word document On Friday, Mar 21, 2003, at 11:51 America/Denver, Gennaro Prota wrote: On Fri, 21 Mar 2003 10:06:45 -0700, Greg Colvin <[EMAIL PROTECTED]> wrote: The idea of the why() member was to preserve context when one exception gets caught and a different one gets thrown, so you could walk back the chain of why()'s asking what() and where(). I bring it up just as a design that might be worth resurrecting if it meets your needs. Do you have pointers to the old std::exception specification, with where() and why() members? PS: I declare myself out of this vague discussion. Just curious about those ones :-) Genny. ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: exception context
On Fri, 21 Mar 2003 10:06:45 -0700, Greg Colvin <[EMAIL PROTECTED]> wrote: >The idea of the why() member was to preserve context when one exception >gets caught and a different one gets thrown, so you could walk back the >chain of why()'s asking what() and where(). I bring it up just as a >design that might be worth resurrecting if it meets your needs. Do you have pointers to the old std::exception specification, with where() and why() members? PS: I declare myself out of this vague discussion. Just curious about those ones :-) Genny. ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: exception context
The idea of the why() member was to preserve context when one exception gets caught and a different one gets thrown, so you could walk back the chain of why()'s asking what() and where(). I bring it up just as a design that might be worth resurrecting if it meets your needs. On Friday, Mar 21, 2003, at 09:24 America/Denver, Alisdair Meredith wrote: Greg Colvin wrote: std::exception used to have a why() member that returned the list of exceptions leading to the one caught. Is that part of what you want? Not exactly. I'm not too bothered about the history of the exceptions, I'm simply concerned with formatting useful error messages for users. In order to describe an error usefully/accurately you need as much context as possible, so such messages are most usefully described/formatted as the exception propogates. If you defer all message-formatting until some outer catch block you need to also leak sufficient implementation detail and knowledge to form that message. In the ideal library, such context information is only accumulated during exception propogation, and would not interfere with the exception handling system at all (no catch blocks, some sort of RAII/ScopeGuard-like object) To that extent, all that is really needed is a known stringstream per thread of execution, and some way to defer diagnostic generation unless an exiting the block due to exception propogation. To an extent, rather than missing why() I am looking for a replacement for what() as well!! Among other things I hear that can cause problems for localising error messages (something else this scheme should address) although I am lucky enough not to have to deal with such problems myself. -- AlisdairM ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: exception context
Greg Colvin wrote: > std::exception used to have a why() member that returned the list of > exceptions leading to the one caught. Is that part of what you want? Not exactly. I'm not too bothered about the history of the exceptions, I'm simply concerned with formatting useful error messages for users. In order to describe an error usefully/accurately you need as much context as possible, so such messages are most usefully described/formatted as the exception propogates. If you defer all message-formatting until some outer catch block you need to also leak sufficient implementation detail and knowledge to form that message. In the ideal library, such context information is only accumulated during exception propogation, and would not interfere with the exception handling system at all (no catch blocks, some sort of RAII/ScopeGuard-like object) To that extent, all that is really needed is a known stringstream per thread of execution, and some way to defer diagnostic generation unless an exiting the block due to exception propogation. To an extent, rather than missing why() I am looking for a replacement for what() as well!! Among other things I hear that can cause problems for localising error messages (something else this scheme should address) although I am lucky enough not to have to deal with such problems myself. -- AlisdairM ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: exception context
std::exception used to have a why() member that returned the list of exceptions leading to the one caught. Is that part of what you want? On Friday, Mar 21, 2003, at 03:58 America/Denver, Alisdair Meredith wrote: Darren Cook wrote: I wanted something like the call stack that shows in python or java when an uncaught exception occurs; if you're also suggesting a snapshot of local vars/parameters then I'll be in heaven and may never need to fire up a debugger again :-). This is exactly NOT what I am interested in though!! For me this is a function of debugger/tools. I specifically want to build up context for a human-readable message to explain why some process failed to the user of the software. The difference is error-handling as opposed to bug-tracking, and it could be there are two libraries (maybe relying on a common subset of behaviour) lurking here. I'm not sure which of these two problems Trevor was proposing to address, but think it is important such a distinction is made early. -- AlisdairM Team Thai Kingdom ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: exception context
Darren Cook wrote: > I wanted something like the call stack that shows in python or java when an > uncaught exception occurs; if you're also suggesting a snapshot of local > vars/parameters then I'll be in heaven and may never need to fire up a > debugger again :-). This is exactly NOT what I am interested in though!! For me this is a function of debugger/tools. I specifically want to build up context for a human-readable message to explain why some process failed to the user of the software. The difference is error-handling as opposed to bug-tracking, and it could be there are two libraries (maybe relying on a common subset of behaviour) lurking here. I'm not sure which of these two problems Trevor was proposing to address, but think it is important such a distinction is made early. -- AlisdairM Team Thai Kingdom ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: exception context
Trevor Taylor wrote: > As a software user I am frequently frustrated by "an error occurred" > like failure messages. As a developer I know that the software *knows* > exactly what failed, why, and exactly what it was doing at the time, but > doesn't pass any of this information on. Alexei Alexandrescu gave a very good sussion on this very topic at last year's ACCU conference. The main thrust of his argument was to make error messages useful to users of the software, rather than try to provide extra context for error-handlers (this should already be part of the library interface, using exception translation if necessary) > I would love boost to provide an exception class/framework/something > with this capability to encourage collection of context information, > which would make problem diagnosis so much easier. Unfortunately, I have not had a chance to evolve an appropriate framework out of this myself yet, and Andrei's scheme for once seemed to rely on a compiler-trick too far! I'm all for stealing some-one else's hard work > Perhaps I could relate some of my experience and put some ideas up > for discussion? I'd certainly be interested. -- AlisdairM ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[boost] Re: exception context
Trevor Taylor wrote: As a software user I am frequently frustrated by "an error occurred" like failure messages. As a developer I know that the software *knows* exactly what failed, why, and exactly what it was doing at the time, but doesn't pass any of this information on. Recently I developed some C++ where for the first time I was happy with the information reported in error cases. The key to happiness, it turned out, was to collect "context" with exceptions as they propogated (back) up the call chain. I would love boost to provide an exception class/framework/something with this capability to encourage collection of context information, which would make problem diagnosis so much easier. IIRC, there was discussion of a library to help getting callstact info etc a few months back, but can't quite remember what the result was. I have basic info on doing this in C++Builder on Windows (and use it in our software) and it could esaily be applied to VC++, but as for other platforms, I'm affraid I can't help. For BCB, have a look at http://www.wischik.com/lu/programmer/index.html and look at the debugging aids section. This could also easily be applied to VC++ as well, but I haven't tried it under that. We use it to generate a callstack in an assert which can be very useful. You could also use it to look up the method name during an access violation or some other exception that can get thrown. I have also had some success using a try...__except block to get the CONTEXT as you mentioned and produce a callstack from that, but usually the last few entries are missing. You can always fill in the last entry for the exception address, but I don't know how much you can trust the stack at that point because, as far as I know, it has started unwinding. I don't think windows keeps a copy of it with the exception record so you can walk it once the exception has been thrown. Cheers Russell Perhaps I could relate some of my experience and put some ideas up for discussion? ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost