[Review:Contract] Contract Broken Handlers , BOOST_NO_EXCEPT and noexcept

Hi, I would like to know if Boost.Contract could work when BOOST_NO_EXCEPT is defined. I suspect that it can not at present, as the user needs to re-throw the exception to know the broken nature. Maybe the handler could have the an exception/error object as parameter instead. In order to be able to use contracts in C++11 functions declared noexcept I would need that the contract handler are declared noexcept also, in particular when the contract is broken from a destructor, which is often declared noexcept in C++11. Maybe the library can provide some specific set handlers that expect a noexcept handler for the destructor context. BTW, could the ALL CAPITAL |FROM_CONSTRUCTOR, ... enumeration literal|s be renamed to lower case from_constructor, ...? Best, Vicente

Le 30/08/12 01:52, Vicente J. Botet Escriba a écrit :
Hi,
I would like to know if Boost.Contract could work when BOOST_NO_EXCEPT is defined. I suspect that it can not at present, as the user needs to re-throw the exception to know the broken nature. Maybe the handler could have the an exception/error object as parameter instead.
Oups, I meant BOOST_NO_EXCEPTIONS (-fno-exceptions) instead of BOOST_NO_EXCEPT. Best, Vicente

On Wed, Aug 29, 2012 at 4:52 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
I would like to know if Boost.Contract could work when BOOST_NO_EXCEPT is defined. I suspect that it can not at present, as the user needs to re-throw the exception to know the broken nature. Maybe the handler could have the an exception/error object as parameter instead.
I'm not sure if this is possible... it will for sure complicate the implementation because I'll have to use status codes so signal failures instead of throw-catch statements. However, there's an issue for user with not using exceptions. Say I change the handlers to pass an object that indicates a contract failure: pre_broken ( contract::from const& context, contract::broken const& failure ) { // ... } If there are no exceptions, this handler can only be called when a contract assertion is evaluated to false in which case failure will be properly set and that's OK: precondition( false ) // calls pre_borken with failure set However, on compilers where exceptions are supported/enabled the handler can also be called if an exception is thrown while evaluating the contract assertion: precondition( f() ) // if f throws, pre_broken is called with an active exception In this case the active exception can be of any type, in general unknown, so the lib can't handle it and convert it into a failure parameter without lost of information (the user instead could program the pre_broken handler with the knowledge of what type of exceptions are thrown by f). In addition users might want to throw their own exceptions: precondition( not empty() : true : throw empty_error() ) Also in this case the lib can't catch and handle the user's exceptions to convert them into the failure parameter. Therefore, when exceptions are present the user will have to look at both active exceptions and the failure parameter in order to properly program the contract broken handlers. IMO, that is more confusing for the user than just having to deal with the active exception (which will be of type contract::broken only when a contract condition is evaluated to false and of some other type when evaluating the assertion condition threw).
In order to be able to use contracts in C++11 functions declared noexcept I would need that the contract handler are declared noexcept also, in particular when the contract is broken from a destructor, which is often declared noexcept in C++11. Maybe the library can provide some specific set handlers that expect a noexcept handler for the destructor context.
OK, I will do this when supporting C++11.
BTW, could the ALL CAPITAL |FROM_CONSTRUCTOR, ... enumeration literal|s be renamed to lower case from_constructor, ...?
Oops, I didn't look what's Boost standard to name enumeration... I'll look it up and fix this if needed. Thanks, --Lorenzo

Le 30/08/12 20:36, Lorenzo Caminiti a écrit :
On Wed, Aug 29, 2012 at 4:52 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
I would like to know if Boost.Contract could work when BOOST_NO_EXCEPT is defined. I suspect that it can not at present, as the user needs to re-throw the exception to know the broken nature. Maybe the handler could have the an exception/error object as parameter instead. I'm not sure if this is possible... it will for sure complicate the implementation because I'll have to use status codes so signal failures instead of throw-catch statements.
However, there's an issue for user with not using exceptions. Say I change the handlers to pass an object that indicates a contract failure:
pre_broken ( contract::from const& context, contract::broken const& failure ) { // ... }
If there are no exceptions, this handler can only be called when a contract assertion is evaluated to false in which case failure will be properly set and that's OK:
precondition( false ) // calls pre_borken with failure set
However, on compilers where exceptions are supported/enabled the handler can also be called if an exception is thrown while evaluating the contract assertion:
precondition( f() ) // if f throws, pre_broken is called with an active exception
In this case the active exception can be of any type, in general unknown, so the lib can't handle it and convert it into a failure parameter without lost of information (the user instead could program the pre_broken handler with the knowledge of what type of exceptions are thrown by f).
In addition users might want to throw their own exceptions:
precondition( not empty() : true : throw empty_error() )
Also in this case the lib can't catch and handle the user's exceptions to convert them into the failure parameter.
Therefore, when exceptions are present the user will have to look at both active exceptions and the failure parameter in order to properly program the contract broken handlers. IMO, that is more confusing for the user than just having to deal with the active exception (which will be of type contract::broken only when a contract condition is evaluated to false and of some other type when evaluating the assertion condition threw). Maybe be we can have both. When BOOST_NO_EXCEPTIONS is defined the broken contract handler interface could have an additional parameter, e.g. the error_code. Not that in this case can not throw of course and any Boost library should avoid code using try/catch or throw sentences.
When BOOST_NO_EXCEPTIONS is not defined, the library will works as now.
In order to be able to use contracts in C++11 functions declared noexcept I would need that the contract handler are declared noexcept also, in particular when the contract is broken from a destructor, which is often declared noexcept in C++11. Maybe the library can provide some specific set handlers that expect a noexcept handler for the destructor context. OK, I will do this when supporting C++11.
The same applies to throw() in C++03. I would expect a different contract for contract broken from the constructor and the others ones. I will comment more about this in a replay to Andrej comment. Best, Vicente
participants (2)
-
Lorenzo Caminiti
-
Vicente J. Botet Escriba