Boost logo

Boost :

Subject: Re: [boost] [dbc] Interest in Design By Contract for C++?
From: Neil Groves (neil_at_[hidden])
Date: 2009-10-18 04:44:34


On Sat, Oct 17, 2009 at 8:04 PM, Lorenzo Caminiti <lorcaminiti_at_[hidden]>wrote:

> Hello all,
>
> Is there any interest in a library that supports Design By Contract
> (DBC) for C++?
>
>
Yes, a Boost version of DbC would be fantastic. I have been using a
half-baked macro solution for years, and would be delighted to assist.

> All DBC features of the Eiffel programming language are supported by
> this library, among others:
> 2) Subcontracting for derived classes.
>

Have you managed to correctly test the derived classes class invariants in
the destructor and constructor?
Is it possible to alter the behaviour when a contract is violated? My
experience shows that it is better to allow more flexibility than simply
terminating the program. I often use exceptions and an exception handling
strategy that allows various objects to be disposed and other objects
invariants to be maintained followed by continuation. This is vital in some
cases where total program termination would be dangerous e.g. flight control
systems. This, of course, introduces problems with how one handles
violations from destructors in particular.
Does your constructor precondition checking occur before initialisation
through the member initialisation list?
Does your invariant checking mandate the use of a virtual function?

3) Use of "old" in postconditions.
>
> EXAMPLE
>
> template<typename T>
> class Stack4 DBC_INHERIT_OBJECT(Stack4<T>) {
> public:
> Stack4(const int& n): capacity_(0), count_(0), representation_()
> DBC_CONSTRUCTOR( (private) (template)(Stack4)( (const int&) (n) ), {
> // Constructor preconditions.
> DBC_ASSERT(n >= 0, "non negative capacity");
> }, {
> // Constructor postconditions.
> DBC_ASSERT(self.now.capacity() == n.now, "capacity set");
> DBC_ASSERT(self.now.empty(), "is empty");
> }, {
> // Constructor body.
> capacity_ = n;
> representation_.resize(capacity_);
> })
>

While I appreciate the intense difficulty in putting these features into C++
the DBC_CONSTRUCTOR and DBC_INHERIT_OBJECT look so foreign that I wonder if
the advantages outweigh the disadvantages of other design alternatives such
as requiring the discipline of the developer to call base functions. If you
are managing to maintain Liskov substitution principle automatically though,
then I might be convinced that this is worth the strange syntax.

<snip>
</snip>

   DBC_INVARIANT(Stack4, {
> DBC_ASSERT(self.count() >= 0, "count non negative");
> DBC_ASSERT_STREAM(self.count() <= self.capacity(),
> "count no greater than capacity",
> err << "count " << self.count() << " bounded by capacity "
> << self.capacity());
> DBC_ASSERT(
> self.capacity() == int(self.representation_.capacity()),
> "capacity consistent with vector capacity");
> DBC_ASSERT(self.empty() == (self.count() == 0),
> "empty when no elements");
> if (self.count() > 0) DBC_ASSERT(
> self.representation_.at(self.count() - 1) == self.item(),
> "if positive count, item at top");
> })
>

The DBC_INVARIANT checking with the ability to add instance information is
excellent and often neglected. This hugely reduces time to defect
resolution. I assume that the same facility exists in the pre and
post-condition assertions.

> };
>
>
<snip>
</snip>

As you can tell, I am extremely keen for a solution that can be standardised
and peer reviewed. I hope you have the time to answer my questions.

Best wishes,
Neil Groves


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