Boost logo

Boost :

Subject: Re: [boost] [contract] Released Contract Programming Library on SourceForge
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2010-03-21 12:40:04


Hello,

On Sun, Feb 28, 2010 at 5:57 PM, Andrzej Krzemienski <akrzemi1_at_[hidden]> wrote:
> I believe, it would be useful if "disabling block invariants" meant no
> run-time overhead, but still checking syntactic correctness. It would
> be possible if the macro

Please see a couple of clarifications on this topic below.

On Mon, Mar 8, 2010 at 9:39 PM, Lorenzo Caminiti <lorcaminiti_at_[hidden]> wrote:
> 1) It still increases compile-time. During development, I find it
> useful to be able to *completely* strip the contracts away, including
> from compilation -- it saves me from waiting extra time to compile
> contract code that I am not executing yet.

In general, it is difficult to assess how much compilation-time will
actually go into the contract assertions because that depends on the
complexity and number of the assertions. This will be different from
project to project.

For a real project I have worked on (~60,000 lines of C++), disabling
assertion compilation reduced compilation-time of about 10%. For that
project, this saving was significant. However, for other projects this
type of saving might not be significant and always checking the
assertion syntax might be more relevant.

> 2) Inv, pre, and post conditions are programmed by the library in
> private member functions (the assertions cannot appear in the body
> because the body might be defined in .cpp separated from the contract
> declaration). I think compilation of these extra member functions will
> still increase the object size (even if if these functions are
> private, called by no one, and they only contain statements like
> `sizeof(expression)` that have no effect) -- I have not verified this.

I have verified this point and I was incorrect. Based on the example I
listed below, the compiler can strip the private/never called contract
function containing the assertions (postconditions in this case).
Therefore, there should be no object code size increase and no
run-time execution overhead even when always checking assertion
syntax. (I will eventually need to confirm this 100% if I implement it
in the library.)

One detail is that, when contracts are *all* turned off, the library
#include <contract.hpp> could only include the preprocessing macros
and none of the library templates so to reduce the object code size.
This will not be possible when always checking assertion syntax
because the library contract::noold and other templates will need to
be available to program the contract functions wrapping the
assertions. Therefore, in the case of all contracts turned off, always
checking assertion syntax will increase a bit the object-size.
However, I think this is not a big deal (only a few of the library
templates will actually be needed).

In summary, given that:
a) The only cost of always checking assertion syntax is extra
compilation-time (but there is no run-time/object-size overhead).
b) Compiling the assertions might take different time for different projects.
[c) Also given the popular responses to the "[boost] suggestion on
assertion macros" email thread...]
I think I should at least consider offering this feature via a
configuration macro. For example, if
CONTRACT_CONFIG_ALWAYS_CHECK_SYNTAX is 1/0 the contract assertions
will always/not-always be compiled to check their syntax. This way
programmers can decide if they can sacrifice some of their compilation
time for this feature or not. What should be
CONTRACT_CONFIG_ALWAYS_CHECK_SYNTAX default value? 0 or 1? (Maybe
1...)
I will add this to the library TODO list.

OBJECT-SIZE ANALYSIS

// File: check.cpp

#include <contract.hpp>

class c {
public:
    struct s {};
    void f(const s& a) {}

#ifdef CONTRACT_ALWAYS_CHECK_SYNTAX
private: // See Without the Macros section in the documentation...
    template< int ZERO >
    void contract_postcondition_f_a_(
            contract::noold,
            typename contract::aux::arg< const s& >::type a,
            contract::noold
            ) const {
        CONTRACT_ASSERT( true );
    }
public:
#endif

};

int main() {
    c().f(c::s());
    return 0;
}

Check syntax on:
 $ g++ -Wall -Werror -I./src -DCONTRACT_CHECK_BLOCK_INVARIANT
-DCONTRACT_CHECK_CLASS_INVARIANT -DCONTRACT_CHECK_PRECONDITION
-DCONTRACT_CHECK_POSTCONDITION -DCONTRACT_ALWAYS_CHECK_SYNTAX
./test/check/main.cpp -o check
 $ ls -l check
     -rwxr-xr-x 1 lcaminiti lcaminiti 8341 2010-03-21 11:52 check
 $ size check
     text data bss dec hex filename
     2051 316 8 2375 947 check
Note the syntax error in case `CONTRACT_ASSERT( true );` is replaced
with `CONTRACT_ASSERT( truex );`:
 $ g++ -Wall -Werror -I./src -DCONTRACT_CHECK_BLOCK_INVARIANT
-DCONTRACT_CHECK_CLASS_INVARIANT -DCONTRACT_CHECK_PRECONDITION
-DCONTRACT_CHECK_POSTCONDITION -DCONTRACT_ALWAYS_CHECK_SYNTAX
./test/check/main.cpp -o check
     ./test/check/main.cpp: In member function ‘void
c::contract_postcondition_f_a_(contract::noold, const c::s&,
contract::noold) const’:
     ./test/check/main.cpp:17: error: ‘truex’ was not declared in this scope

Check syntax off (same `size check` results as above):
 $ g++ -Wall -Werror -I./src -DCONTRACT_CHECK_BLOCK_INVARIANT
-DCONTRACT_CHECK_CLASS_INVARIANT -DCONTRACT_CHECK_PRECONDITION
-DCONTRACT_CHECK_POSTCONDITION -UCONTRACT_ALWAYS_CHECK_SYNTAX
./test/check/main.cpp -o check
 $ ls -l check
     -rwxr-xr-x 1 lcaminiti lcaminiti 8341 2010-03-21 11:53 check
 $ size check
    text data bss dec hex filename
    2051 316 8 2375 947 check
Note no syntax error in case `CONTRACT_ASSERT( true );` is replaced
with `CONTRACT_ASSERT( truex );`:
 $ g++ -Wall -Werror -I./src -DCONTRACT_CHECK_BLOCK_INVARIANT
-DCONTRACT_CHECK_CLASS_INVARIANT -DCONTRACT_CHECK_PRECONDITION
-DCONTRACT_CHECK_POSTCONDITION -UCONTRACT_ALWAYS_CHECK_SYNTAX
./test/check/main.cpp -o check

Regards,
Lorenzo


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