Boost logo

Boost :

Subject: Re: [boost] [contract] Without the macros
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2016-06-24 18:49:33


Hi Andrzej!

On Fri, Jun 24, 2016 at 2:43 PM, Andrzej Krzemienski <akrzemi1_at_[hidden]> wrote:
> 2016-06-15 17:30 GMT+02:00 Lorenzo Caminiti <lorcaminiti_at_[hidden]>:
>
>> While doing so I realized that leveraging C++11 lambda functions,
>> Boost.Contract could be re-implemented without its crazy macros that
>> alter C++ function declaration syntax.
>
> If I understand correctly, the change you propose moves the assertions from
> function declaration into function definition. If this is the case, I would
> say it is a step in wrong direction. Pre-/post-conditions are part of
> function contract and belong in function declaration.

True this a downside of the new version, but that removes the crazy
macros which I consider more important in using the library than
keeping contracts with function declarations. If you are willing to
manually repeat the function signature, you cal leave a small function
definition in header files that will just program the contracts and
then calls the body. That emulates keeping contracts with function
declarations to the extent they will be clearly visible from the
header files that are shipped with the compiled code:

``Contracts are part of the program specification and not of its
implementation (see also Specification and Implementation). However,
this library uses function definitions to program the contracts so
contract code appears together with the function implementation code.
...''

https://lcaminiti.github.io/boost-contract/doc/html/boost_contract/advanced_topics.html#boost_contract.advanced_topics.separate_body_implementation

> Also, from the example, it looks like I will have to pay for the existence
> of `boost::contract::old_ptr` and `boost::contract::guard` (and compiler
> warnings related to them) even if I disable contracts. Is that right?

Yes, you'll pay the cost of declaring a smart pointer for old_ptr that
will be assigned to null in this case (no old value copy is actually
done when postconditions are disable) and a contract guard that will
do nothing. The library implementation code is optimized to remove all
internal members, etc. so these objects are rather simple when
contracts are disable, but they are still there.

> I do not know what the previous macros did, but I had the impression that they
> were able to erase any track of contract-related objects.

Yes, the old macros where able to completely erase contract code from
user code when contracts were disabled. With the new version you can
do that manually if that is truly needed:

https://lcaminiti.github.io/boost-contract/doc/html/boost_contract/advanced_topics.html#boost_contract.advanced_topics.disable_contract_compilation

However, in my experience if a piece of code is very critical for
performance then I don't program contracts for it (because even the
cost of checking preconditions might not be acceptable). Most of the
code however is not that performance-critical, I program contracts for
it, and if this contract code declares an extra empty pointer and
guard even when contracts are disabled that's not an issue in practice
(plus I usually leave preconditions and entry invariants enabled even
in code that is shipped).

> Also, the way you use the return value, forces me to depart from how I
> normally write return statements.
>
> While the new version is clearly more readable, it also has certain
> important disadvantages compared to the previous version.
> What more do the new version of pre/postconditions offers compared to putting two asserts at
> the beginning and the end of the function?

Old values, class invariants, and subcontracting (in increasing order
of implementation complexity).

> Preconditions are evaluated after local object's destructors. What you propose is addressing the
> subject from a different anle, but is not necessarily superior to the
> previous version.

Absolutely correct, there is a trade-off between the old and new
version (I think I pointed that out in the docs even if not in a
direct comparison with the old macro interface, I will do that
comparison in the Release Notes section).

That said, the crazy macro syntax, long compilation/preprocessing
times, and cryptic compiler/preprocessor errors were major blockers
for adopting the old library in real code. The new library no longer
suffers from these issues so I hope it can be more widely used. I
consider that a fare trade-off with respect to the cost of not having
contracts in declarations and small run-time overheads associated with
empty old_ptr and guard when contracts are all disabled (also
programmers can manually program extra code to get around these
limitations in sections of the code where they really are limiting in
practice).

Thanks,
--Lorenzo


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk