C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Design By Contract

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Michael D. Borghardt
Guest





PostPosted: Fri Sep 26, 2003 11:00 am    Post subject: Design By Contract Reply with quote



Hi I am looking at this from a clients perpective

void main()
{
Base * base = new Base();
DerivedFromBase * derived = new DerivedBase();

// Function documented that parameter must be greater than 5
base->foo(X);

// Function documented that parameter must be greater than 3
derived->foo(X);

. . .

Base * converted = derived;

// What do you think the client expects
converted->foo(X);
}

What I and really trying to figure out is how preconditions can be inherited
when conversion takes place.

Since converted ISA base then wouldn't a client have to used the method with
the assumption from class Base that it must be > 5?

I know this may more of an OO than a C++ questions but I have some
implementation ideas that would follows given the answers that I receive.




[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
WW
Guest





PostPosted: Sat Sep 27, 2003 10:33 am    Post subject: Re: Design By Contract Reply with quote



Michael D. Borghardt wrote:
Quote:
Hi I am looking at this from a clients perpective
[SNIP]
DerivedFromBase * derived = new DerivedBase();

// Function documented that parameter must be greater than 5
base->foo(X);

// Function documented that parameter must be greater than 3
derived->foo(X);
[SNIP]
What I and really trying to figure out is how preconditions can be
inherited when conversion takes place.

Since converted ISA base then wouldn't a client have to used the
method with the assumption from class Base that it must be > 5?
[SNIP]


IMO it is simple. The client (haveing a Base *) has absolutely no idea
about the existence of Derived, and its relaxed preconditions. If you are
serious about the interface and the preconditions of Base, you *must not*
allow to go through it anything, but what confroms to it. Why? Because the
client has no idea what derived class is behind Base *. So if a fault
(passing 4 or 5) happens to happen in your unit test environment only for
this Derived (relaxing the the precondition) it is in no way a guarantee
that it won't blow into the face of your most important customer by passing
4 to a Derived2, which only accept values of 5+.

I believe that the right way to look at this is to imagine the Base as an
interface. With no virtual functions! This interface is a handle, it has a
pointer inside to the real thing, which has the virtuals. So we have
separated in our C++ minds the interface from the implementation. The
interface is static, the implementation is dynamic. (Afraid to say: sounds
like sun-burnt coffee. No, I will not tell the word and wash my mouth with
soap again. Wink )

So. We have an interface and an implementation. Where does the
precondition go? Into the interface (the only thing the client knows about)
or into the implementation? Is the precondition part of the interface I
define? Should I tell about it to the client? IMO the answer is _yes_.
That means, that the precondition must go into the static interface. It
also means: it must not change (as long as the interface is used) depending
on what implementation is there.

Let's play a bit more with the thought. Where do postconditions go? Well?
IMHO if the postcondition is "visible" to the client, it should go to the
interface, emaning that it should be static. Let's fast define what does
visible mean here. Two thing: it can be defined in terms of the interface
and I *want* to tell about it to the client, so it is part of my interface
(the things I promise). Derived implementations might harden that part of
the postcondition, but thsi also means they will (LSP) always provide the
one the interface promises. They cannot weaken it. And a client, knowing
*only* the interface (the "common promse") cannot and must not depend on the
stronger promises of the individual derived classes. I was thinking if
there is anything else I could call postcondition. I believe there isn't.
Whatever is not a pre- or postcondition explainable in terms of the
interface is an (implementation specific) invariant.

How about invariants? Well, IMHO there are two kinds of them. One is what
I shall call domain specific invariant. This is what can be defined in
terms of the interface and which is part of all the the pre- and the
postcondition I promise to the client. This is the "std::set_intersection"
of all the pre and postconditions. (I did not start to think about
invariants around a pair of corresponding pre- and postcondition, there
might be such a thing, too.)

The second kind of invariant is the implementation invariant. It cannot be
defined in terms of the interface, it makes some more deep checking of the
private implementation than the client-invariant can. For the same reason
there can be implementation postconditions as well, especially with classes,
which have more functionality inside than the client knows about. So they
need to make some meaningful integrity check, what cannot be done only using
the client-interface. Classes with "hidden functionality" like COW or any
other form of late evaluation etc. can be such.

I am very proud of what I wrote here. Of course, it may be bullshit. If
you think it is, please be very gentle when telling - I am just starting to
gain back my long lost self-confidence. Also because it became rather a
theroretitcal discussion of my beliefs (and it is hard to see more/else than
the picture you see as "perfect") please also give real life examples, when
you think this "categorization" I have made would not work.

--
WW aka Attila



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Marcelo Pinto
Guest





PostPosted: Sat Sep 27, 2003 2:07 pm    Post subject: Re: Design By Contract Reply with quote



"Michael D. Borghardt" <michael (AT) borghardtConsulting (DOT) net> wrote

[snip]
Quote:
void main()
should be int main()
{
Base * base = new Base();
DerivedFromBase * derived = new DerivedBase();

// Function documented that parameter must be greater than 5
base->foo(X);
what is X?

// Function documented that parameter must be greater than 3
derived->foo(X);

. . .

Base * converted = derived;

// What do you think the client expects
converted->foo(X);
}

What I and really trying to figure out is how preconditions can be inherited
when conversion takes place.

Since converted ISA base then wouldn't a client have to used the method with
the assumption from class Base that it must be > 5?

I know this may more of an OO than a C++ questions but I have some
implementation ideas that would follows given the answers that I receive.

In his book, Agile software development: principles, patterns and
practices, Robert Martin treats this problem in chapter 10. And there
is no problem with the converted part since it will only recieve
values that are greater than 5, which satisfies the precondition of
both classes in the hierarchy.

If the preconditions were the opposite than you would be violating the
Liskov Substitution Principle.

Regards,

Marcelo Pinto

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Siemel Naran
Guest





PostPosted: Sat Sep 27, 2003 2:13 pm    Post subject: Re: Design By Contract Reply with quote

"Michael D. Borghardt" <michael (AT) borghardtConsulting (DOT) net> wrote in message

Quote:
// Function documented that parameter must be greater than 5
base->foo(X);

// Function documented that parameter must be greater than 3
derived->foo(X);

Base * converted = derived;
converted->foo(X);

Since converted ISA base then wouldn't a client have to used the method
with
the assumption from class Base that it must be > 5?

You're safe. If it is >5 then it is also >3.

There's a rule that when you inherit classes, then the derived class
precondition should be equal to or stronger than the base class
precondition.

There's also this common design pattern: a non-virtual public function that
calls a non-virtual precondition check function, then a virtual do function,
then a non-virtual postcondition check function. This implies the pre and
post conditions remain the same between base and derived classees.

--
+++++++++++
Siemel Naran



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
James Kanze
Guest





PostPosted: Sat Sep 27, 2003 5:08 pm    Post subject: Re: Design By Contract Reply with quote

"Michael D. Borghardt" <michael (AT) borghardtConsulting (DOT) net> writes:

Quote:
Hi I am looking at this from a clients perpective

void main()

Just for the record, that should be "int main()".

Quote:
{
Base * base = new Base();
DerivedFromBase * derived = new DerivedBase();

// Function documented that parameter must be greater than 5
base->foo(X);

// Function documented that parameter must be greater than 3
derived->foo(X);

. . .

Base * converted = derived;

// What do you think the client expects
converted->foo(X);
}

What I and really trying to figure out is how preconditions can be
inherited when conversion takes place.

In C++, preconditions are up to the programmer. You do what you want.

The standard rule (LSP) is that preconditions can be loosened, and
postconditions strengthened, in a derived class. The basic rule is
that the derived class can be used anywhere the base class can. (It may
be possible to use it in places where the base class cannot be used, but
the inverse should not be true.)

Quote:
Since converted ISA base then wouldn't a client have to used the
method with the assumption from class Base that it must be > 5?

It depends on how the programmer implements his preconditions. By
default, C++ makes no assumptions -- if you, as a user, know that the
actual object is a derived, and call the function with 4 as a parameter,
C++ doesn't care.

In Eiffel (the only language I know where concepts like preconditions
and postconditions are part of the language), a derived class can
declare looser preconditions, and tighter postconditions, and at run
time, it is the derived class checks which will be applied. (I believe
that the compiler verifies that the preconditions are not tighter.)

In C++, my own preference is to consider that loosened preconditions or
tightened postconditions represent a new (more liberal) contract. And
create a derived interface which implements this contract, and require
that the client code explicitly say that it wants to use this more
liberal interface. The specification occurs in a derived abstract
class, and the client says that he wants to use it by means of a
dynamic_cast. (This, of course, supposes that the interfaces use my
usual idiom for enforcing contracts -- non-virtual public functions
which contain the enforcement code and call private or protected virtual
functions for the actual implementation.)

To give a concrete example, based on the above:

class Base
{
public:
void foo( int x )
{
assert( x > 5 ) ;
doFoo( x ) ;
}
private:
virtual void doFoo( int x ) = 0 ;
} ;

class Derived : public Base
{
public:
void foo( int x )
{
assert( x > 3 ) ;
doFoo( x ) ;
}

private:
virtual void doFoo( int x ) = 0 ;
} ;

A concrete class may derive from Base or Derived, depending on whether
it wants to implement the (stricter) contract in the base class, or the
more liberal contract in Derived. If a user is given a Base*, but wants
to use the more liberal contract, it should do something like the
following:

Derived* pD = dynamic_cast< Derived* >( pB ) ;
assert( pD != NULL ) ;
pD->foo() ;

--
James Kanze mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Michael D. Borghardt
Guest





PostPosted: Tue Sep 30, 2003 10:40 am    Post subject: Re: Design By Contract Reply with quote

Hi.

Thanks for you opinion

So here is the idea taken from various places

Part of assertions.h

// Customed assertion handler
void onAssertion__(char const * expression, char const * file, unsigned
line);

// Create filename string once per source file
#define DEFINE_THIS_FILE
static char const THIS_FILE__[] = __FILE__;

// Base Assertion that calls assertion handler if false
#define ASSERTION(test_)
((test_) ? (void)0 : onAssertion__(#test_, THIS_FILE__, __LINE__))

// tests that causes Side-effects
#define ALLEGE(test_) ASSERTION(test_)

// Preconsitions
#define REQUIRE(test_) ASSERTION(test_)
// Postconditions
#define ENSURE(test_) ASSERTION(test_)
// Invariants
#define INVARIANT(test_) ASSERTION(test_)
#endif

base.h

class Base
{
public:
void func(int i)
{
INVARIANT(invariant());
// preconditions
REQUIRE(i > 0);
funcImp();
// postconditions
ENSURE(i > 0);
INVARIANT(invariant());
}
protected:
// protected and pure so it must implement in derived and must call this
classes function
virtual bool invariant() = 0 {return true;}

void funcImp() { funcImp1(); funcImp2();}
private:
// must be implemented in derived but cannot call this classes function
virtual void funcImp1() = 0;
virtual void funcImp2() = 0;
};

Part of derived.h

class Derived : public Base
{
public:
void func(int i)
{
INVARIANT(invariant());
// preconditions
REQUIRE(i >= 0);
funcImp();
// postconditions
ENSURE(i >= 0);
INVARIANT(invariant());
}
protected:
virtual bool invariant() {return Base::invariant() && true;}
private:
virtual void funcImp1();
virtual void funcImp2();
};

The good thing I see about this is that the DBC is defined in the header
file that others can see

The Bad thing I see is that the conditions are not enfored to weakened or
strengthened at compile-time so it it up to the programmer to ensure the
correct context.

Another bad thing is that In the dreived class it does not have access the
base class condtions AND private variables

So I am startign to think that I will have to have pre and post condtion
functions that can be called up the hierarchy and OR the precondtions and
AND the post conditions

From an implementation point of view I see this as a grand preprocessor
exercise, any thoughts.


BTW Does anyone know if/how Eiffel makes sure the conditions do not conflict
eash other ie

in base require i >0 and in derfived require i < 0


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Adam H. Peterson
Guest





PostPosted: Tue Sep 30, 2003 8:50 pm    Post subject: Re: Design By Contract Reply with quote

<snip>
Quote:
class Base
{
public:
snip
protected:
// protected and pure so it must implement in derived and must call this
[ // ] classes function
virtual bool invariant() = 0 {return true;}

snip
};

Note that the above is not correct C++. In particular, C++ doesn't
allow the implementation of a pure virtual function to be given in the
class body. (It's a violation of the grammar, although Visual C++
accepts it.) It must either be given inline afterward or in a .cpp file
separately. (I would prefer inline afterward, so it's obvious to the
client that the function _has_ a definition.)


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Javier Estrada
Guest





PostPosted: Fri Oct 03, 2003 11:32 am    Post subject: Re: Design By Contract Reply with quote

Michael,

I think a more correct forum would be one with OO. There are several
methodologists active in other newsgroups that deal with some of these
concepts.

A design pattern that deals with your post is the Percolation Pattern.
It is published in the book Testing Object-Oriented Systems, by V.
Binder and also appeared in C++ Report a few years ago.

In addition, the design by contract concepts are nicely tackled in,
well, design Smile. The Object Constraint Language, now part of UML,
gives some guidelines that can be used for invariants, preconditions
and postconditions. I'll try to summarize them here:

- An invariant for a superclass is inherited by its subclasses. A
subclass may strengthen the invariant but cannot weaken it.

- A precondition may be weakened, not strengthened, in a redefinition
of an operation in a subclass.

- A postcondition may be strengthened, not weakened, in a redefinition
of an operation in a subclass.

The Percolation Pattern basically adheres to these statements in the
presence of class hierarchies and multiple inheritance.

Here's the Amazon link for the books:

http://www.amazon.com/exec/obidos/external-search/104-5230100-9933527?tag=opera-20&index=blended&keyword=Testing+Object-Oriented+Systems

I couldn't get the other link. It seems somebody hacked amazon--it
displays FOO :-)

Regards,

Javier Estrada

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
John Kewley
Guest





PostPosted: Fri Feb 06, 2004 8:49 pm    Post subject: Re: Design by Contract Reply with quote

Quote:
- An invariant for a superclass is inherited by its subclasses. A
subclass may strengthen the invariant but cannot weaken it.

- A precondition may be weakened, not strengthened, in a redefinition
of an operation in a subclass.

- A postcondition may be strengthened, not weakened, in a redefinition
of an operation in a subclass.

This agrees with the Eiffel model if I remember it correctly.
It also agrees with LSP.

Another thing to bear in mind with LSP is exceptions.
Making specifications about which exceptions you can or can't return are
affecting your post-condition and the possibility of substitution by a
derived class,
were their specifications to differ. [although maybe C++ now specifies how
exception specifications from base class methods propogate to derived class
methods]

JK




[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.