> > 4. In case an assertion has failed, two actions will occur: > > - first, the assertion will be logged > > - second, a message will be show to the user, and the user can choose from > > multiple actions, like Ignore, Retry, Abort, etc. > > > > These are SEPARATE actions, and are both customizable. > > Customization can happen at RUNTIME. > > In my own assert library I added options for logging, but in the end never > used that and always had it throw an exception. This is nice for two reasons: > 1. MFC debugger catches it and allows me to go back up the call stack to > where the assert happened. (I'm still struggling with gdb but I think it can > be set to do the same?) > > 2. Boost::test will catch the exception; if I want to test a function > asserts with bad inputs I can use BOOST_CHECK_THROW. > > So I'd like to see three separate actions, and be allowed to switch off the > first two (with a compile-time flag). > > Given that, I'm wondering if instead of hard-coding two or three actions > that can be customized if you wouldn't be better allowing any number of > callbacks to be registered, and then supplying some ready-made callbacks to do: > 1. logging > 2. user prompting > 3. throw exceptions
Basically, the N actions will be able to be customized (that is, you'll be able to add your own levels). What you say, about throwing an exception, also will be possible, since you'll be able to set a "handler" for each level of assertion. So, for instance, for assertions with level Debug (default), you can set a handler that will throw. Just like that! At run-time! (you can leave the default handler for assertions, that will prompt the user, etc. , or just set your own, which can throw an exception). > > ------------------------ > > 10. specifying all ASSERT's arguments > > > > When using BOOST_ASSERT, you should specify all arguments involved in the > > assert; otherwise, if the assertion fails, you might not get enough > > information. > > > > Example: > > // OK - all 3 params have been cared for > > BOOST_ASSERT( (i > 1) || (j < 0) || (k != i) )(i)(j)(k); > > > > // bad - in case an assertion fails, not enough info is outputted! > > // (k is not outputted) > > BOOST_ASSERT( (i > 1) || (j < 0) || (k != i) )(i)(j); > > > > (compile-time switch, can be on/off; on by default) > > I didn't follow this one - are you saying the compiler will complain about > the bad assert that doesn't include "(k)"? If you could do that you wouldn't > need the user to specify the variables at all would you? Unfortunately, finding out if all of the arguments have been set or not cannot happen at compile-time. I knew that ;-) The switch is compile-time, meaning that: - if on, at RUNTIME, I'll check if all arguments have been specified - if off, I won't check anything. Of course, I thought about this, and cannot find a solution that would allow this checking to happen at the beginning of the program (in other words, this will happen only the first time the code reaches an ASSERT). Anyway, if you know of a way, please let me know! > > > > We can have a "fatal error" level, in which case an exception could be > > triggered. > > I thought all asserts should be considered fatal, so as suggested above I > think BOOST_ASSERT should always throw an exception, and maybe you need > BOOST_WARNING for non-fatal conditions you'd like logged or to inform the > user about. Not true (in my oppinion). It happens that code might be "over-ASSERTed" (sometimes, some ASSERTs are not needed). What has happened to me was that I developed some code, and others have picked up and continued developing it. Some of the initial constraints have been loosened, therefore, some of the ASSERTs became unnecessary. Had such an ASSERT throw, some handler might catch it, and this could go undetected. What do you think? > > > I'll allow for custom printing of variables (when an assertion fails). > > ... > > For instance, for a non-null pointer, you might want to print (some of) its > > contents. Or, for an STL container, to print its elements (or at least its > > size) > > This is interesting; what syntax do you have in mind for using this? > > For some types of objects it might be useful to specify a function to call > if it asserts; I often have a debug_info() function in my classes. E.g. > BOOST_ASSERT(obj.status()==0)(obj.debug_info()) > > Will that work if debug_info() returns void? It should. I was thinking of a general class, like: class print_obj { // with some specializations template< class type> void do_print( const type & val) { ...} }; In case you're wondering why a class and not a function, is because I would like it to hold context. For example, you might want something like this: ASSERT( *first != *last)(boost::assert_range)(first)(last); In case the assertion fails, I could log the whole first-to-last range. Had the printer been a function, this would have not been possible. As a bonus, you'll be able to write/derive your own printer class that will do the printing (and I'll provide a few to choose from ;-)). > > Darren > > P.S. I like everything else you proposed, and the BOOST_ASSERT name is fine. Thanks. > Though if aiming for inclusion in C++ standard in the future maybe > SMART_ASSERT or similar is better? Yes, I do prefer SMART_ASSERT as well. Best, John _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost