Design by Contract for abstract base class?

K

kk_oop

Hi. I'm looking to find a way to apply Design by Contract in my C++
programs.

The problem that I'm having deals with pure abstract base classes.
Since these are often how an object gets exposed to clients via
polymorphism, it seems critical that an abstract base class can define
and enforce its contracts. Defining contracts is critical, so LSP can
be utilized when defining derived implementation classes. However, if
the pure abstract base class defines a method to enforce its contract,
it will no longer be pure abstract. This poses a problem, for instance,
if the abstract class is being used to apply multiple interface
inheritance. In that case, the abstract class really needs to be pure
abstract.

Is there a way for C++ to somehow enable an pure abstract base class to
enforce its contracts? Seems like an unfixable paradox.

Any thoughts?

Thanks,

Ken
 
D

David White

kk_oop said:
Hi. I'm looking to find a way to apply Design by Contract in my C++
programs.

The problem that I'm having deals with pure abstract base classes.
Since these are often how an object gets exposed to clients via
polymorphism, it seems critical that an abstract base class can define
and enforce its contracts. Defining contracts is critical, so LSP can
be utilized when defining derived implementation classes. However, if
the pure abstract base class defines a method to enforce its contract,
it will no longer be pure abstract. This poses a problem, for instance,
if the abstract class is being used to apply multiple interface
inheritance. In that case, the abstract class really needs to be pure
abstract.

Is there a way for C++ to somehow enable an pure abstract base class to
enforce its contracts? Seems like an unfixable paradox.

I don't know if I can help because I don't know what you are talking about.
This is a C++ (and, incidentally, a plain text) newsgroup, but I don't see
much in your post beyond a whole lot of OO jargon. If you have a C++
question, and you can ask it in _plain_ language, and without undefined
abbreviations such as 'LSP', please ask it.

In the meantime, I'll have a stab at answering this part: "However, if the
pure abstract base class defines a method to enforce its contract, it will
no longer be pure abstract."

// abstract class
class Base
{
public:
virtual void f() = 0; // pure virtual
};

// implementation of pure virtual
void Base::f()
{
}

// concrete class
class Derived : public Base
{
public:
void f() {} // override Base::f()
};

int main()
{
Derived d; // okay
Base b; // error; Base::f() pure virtual
}

The point is that Base is still abstract, or "pure abstract" as you put it,
even though Base "defines a method" for its only pure virtual function.

DW
 
J

jeffc

David White said:
I don't know if I can help because I don't know what you are talking about.
This is a C++ (and, incidentally, a plain text) newsgroup, but I don't see
much in your post beyond a whole lot of OO jargon. If you have a C++
question, and you can ask it in _plain_ language, and without undefined
abbreviations such as 'LSP', please ask it.

OO jargon is obviously part of C++, since C++ is an OO language. LSP is
Liskov Substitution Principle, which basically says that inheritance should
be used when a subclass object can be substituted for a base class object,
and the code would still work the same.
In the meantime, I'll have a stab at answering this part: "However, if the
pure abstract base class defines a method to enforce its contract, it will
no longer be pure abstract."

He might be confusing "pure abstract" with "pure virtual", or there might be
an OO term that would translate in C++ terms to "a base class with a pure
virtual function that has no function definitions". Or, as you said, he
might not be aware that abstract classes can have function definitions while
still not allowing any instances to be created. I'd ask the OP what his
definition of "abstract class" is, at this point.
 
D

David White

jeffc said:
OO jargon is obviously part of C++, since C++ is an OO language.

Yes, but I've never see so much OO jargon in discussions of C++ features.
What exactly does it mean for an abstract base class to "define and enforce
its contracts"? Is "multiple interface inheritance" simply multiple
inheritance? The OP is speaking a language that I don't recall most of the
C++ experts in this newsgroup ever speaking.
LSP is
Liskov Substitution Principle, which basically says that inheritance should
be used when a subclass object can be substituted for a base class object,
and the code would still work the same.

I have a colleague who is usually brilliant at recalling the meanings of the
most obscure abbreviations used in a range of computing-related areas. If I
come across one I don't know, I call out, "What does <insert abbrev> mean?"
and he can nearly always tell me. He and I are also project leaders and OO
designers and implementers of about 10 years experience. Neither of us knew
what "LSP" meant. The principle itself seems rather obvious to me and I use
it all the time, but I don't feel as though I've missed anything important
in not knowing its name.

DW
 
K

Ken

jeffc said:
He might be confusing "pure abstract" with "pure virtual", or there might be
an OO term that would translate in C++ terms to "a base class with a pure
virtual function that has no function definitions". Or, as you said, he
might not be aware that abstract classes can have function definitions while
still not allowing any instances to be created. I'd ask the OP what his
definition of "abstract class" is, at this point.

Hi. What I was trying to refer to is a class that has only pure
virtual methods and no data. What is the term for that in C++? In
Java and UML it's an interface.

Anyway, perhaps that puts my original question in a clearer context?
My understanding of C++ (based on Scott Meyers' Effective C++) is that
multiple inheritance should only be done for interface base classes
(using my definition of interface class above). By adding a contract
verification method to the interface base class, it should no longer
be used in multiple inheritance relationships, since it would have
implementation. But if you don't define these contract verification
methods in the base class, you'd have to define them in every instance
of the derived classes. Perhaps not a bad thing. Or perhaps there's
another way to do this--maybe with ASSERTs?

If that adds some clarity, are there any suggestions or comments?

Thanks again,

Ken
 
D

David White

Ken said:
"jeffc" <[email protected]> wrote in message

Hi. What I was trying to refer to is a class that has only pure
virtual methods and no data. What is the term for that in C++? In
Java and UML it's an interface.

I don't know, but I doubt it has a different name in C++. I've never paid
much attention to whether a class that only has pure virtual functions has
data members or not, because I don't see how that makes a fundamental
difference to it either way.
Anyway, perhaps that puts my original question in a clearer context?
My understanding of C++ (based on Scott Meyers' Effective C++) is that
multiple inheritance should only be done for interface base classes
(using my definition of interface class above).

I haven't read it, but that sounds a bit odd to me. I've hardly ever used
multiple inheritance for any purpose. It just seems unwieldy and inelegant
to me, but if I were to use it I don't see why it should be restricted to
interface classes.
By adding a contract
verification method to the interface base class, it should no longer
be used in multiple inheritance relationships, since it would have
implementation.

I think it's necessary to fully understand the reason for what "should" no
longer be done. If there's a compelling reason that multiple inheritance
should not be used just because you add implementations for pure virtual
functions, I can't guess what it is. Do what works unless someone can
identify why it shouldn't be done.
But if you don't define these contract verification
methods in the base class, you'd have to define them in every instance
of the derived classes. Perhaps not a bad thing. Or perhaps there's
another way to do this--maybe with ASSERTs?

Can you give an example of what a contract-verification method does,
preferably with some real code?

DW
 
K

kenandeva

DW:

For info on contracts and LSP, see: http://ootips.org/lsp.html

It's got some cross reference links to additional info.

You can look at LSP almost like a design pattern, in that it's a good
practice that lots of good OO designers do without giving it a name.
Barbara Liskov gave it a name and wrote a paper about it, so, just like
with a design pattern, the name she gave stuck--and it just happens to
include her own name (as in Liskov Substitutability Principle). Save
that for the OO version of Trivial Pursuit. :) Though I do find it
useful to just refer to the concept as LSP, just like calling a
Singleton a Singleton is easier that describing what it means every time
you need to bring it up.

If you want to see her original paper (I wouldn't recommend it--it's
very dense. The OO tips links are much more readable.), it's called: A
Behavioral Notion of Subtyping. Doing a Google search reveals many PDF
versions suitable for framing and giving as gifts this holiday season :).

My questions have to do with defining the contracts used to verify
LSP--namely should they just be comments in a method or class abstract,
or can/should they be actually included in the code via ASSERTs or
contract verification methods.

See ya,

Ken
 
J

jeffc

David White said:
Yes, but I've never see so much OO jargon in discussions of C++ features.

That was quite a load :)
I have a colleague who is usually brilliant at recalling the meanings of the
most obscure abbreviations used in a range of computing-related areas. If I
come across one I don't know, I call out, "What does <insert abbrev> mean?"
and he can nearly always tell me. He and I are also project leaders and OO
designers and implementers of about 10 years experience. Neither of us knew
what "LSP" meant. The principle itself seems rather obvious to me and I use
it all the time, but I don't feel as though I've missed anything important
in not knowing its name.

Yes, the principle is sometimes called just "substitutability", as in C++
FAQs. Someone (Liskov?) decided someone needed credit for it. I don't
think you've missed anything either.
 
J

jeffc

kenandeva said:
My questions have to do with defining the contracts used to verify
LSP--namely should they just be comments in a method or class abstract,
or can/should they be actually included in the code via ASSERTs or
contract verification methods.

ASSERTs are pretty much a waste of time, since they only affect debug code
(I've never been much of a fan of ASSERT). Comments would be good, but they
can never be enforced (I know, I tried - that was my job for about 6 months
one time.)
 
J

jeffc

Ken said:
"jeffc" <[email protected]> wrote in message

Hi. What I was trying to refer to is a class that has only pure
virtual methods and no data. What is the term for that in C++? In
Java and UML it's an interface.

I don't think there is a term for that in C++ because there's nothing to
enforce it. An abstract class can have data.
Anyway, perhaps that puts my original question in a clearer context?
My understanding of C++ (based on Scott Meyers' Effective C++) is that
multiple inheritance should only be done for interface base classes
(using my definition of interface class above).

Maybe I'm not the best person to ask because I'm not sure I agree with him.
You might ask on comp.object. Even though you're asking about C++
specifically, that shouldn't throw them off.
 
?

=?iso-8859-1?Q?Juli=E1n?= Albo

jeffc escribió:
ASSERTs are pretty much a waste of time, since they only affect debug code
(I've never been much of a fan of ASSERT). Comments would be good, butthey

An assert is a comment that is enforced at debug time.

Regards.
 
L

lilburne

jeffc said:
ASSERTs are pretty much a waste of time, since they only affect debug code
(I've never been much of a fan of ASSERT). Comments would be good, but they
can never be enforced (I know, I tried - that was my job for about 6 months
one time.)

Someone came for an interview with us once and said they
were just starting to use exceptions in their code, one of
the interviewers growled "We don't like fucking exceptions,
and you won't be fucking well throwing any here".

I'll attempt to be more diplomatic but it may be hard to
disguise my disgust.

When we last looked into exceptions we discovered a 14-18%
performance degradation due to the code that was being
inserted to handle stack unwinding. Things may be different
now, but at the time we found that alone to be an
unacceptable price to pay.

We are also deeply suspicious of the use of exceptions to
enforce class contracts. We simply do not believe, for
example, that failure to honour a precondition is an
exceptional condition: it is a BUG.

Throwing exceptions because function arguments are out of
range, or invalid seems to be an abomination particularly
prevalent amongst programmers schooled in java, or at least
recent CS graduates. The problem with this style of
programming is that you are forcing customers of your
runtime system to pay a price for the fact that the caller
couldn't or wouldn't honour a methods published contract.

Our code is heavily laced with assertions. Each method will
assert that its preconditions have been met and that the
state invariant is valid, some parts of our code run 20x
slower in debug than release due to such checks. Using
exceptions for these checks would place that burden into the
customer releases, that is totally unacceptable, and we
would not consider code that did not perform such checks was
of adequate quality.

If someone passes me a point or vector in 3d space I expect
it to be properly initialized not to hold some crappy value
due to a default construction and I don't need to do
millions of such checks in a customer release. One thing
that does amuse is that those using exceptions the most,
tend also to be those that think that inlining a set method
will speed up their application, or worry over the speed of
'++i' vs 'i++' when i is an int.

I'm sure that there are plenty of valid reasons for using
exceptions, I just don't think those reasons are as
prevalent as people think, and they haven't been found in
the applications we write.

BTW the interviewee got the job.
 
K

Ken

lilburne said:
Our code is heavily laced with assertions. Each method will
assert that its preconditions have been met and that the
state invariant is valid, some parts of our code run 20x
slower in debug than release due to such checks. Using
exceptions for these checks would place that burden into the
customer releases, that is totally unacceptable, and we
would not consider code that did not perform such checks was
of adequate quality.

That last sentence threw me off. Too many nots for my little brain
:). Are you saying that code that performs the checks as exceptions
is not acceptable?

I do agree that exceptions are overused to identify "normal" error
conditions--namely errors which are not due to a bug in the software.
But if the error is actually a bug, it probably shouldn't be happening
too often, and when it does--that path of the software shouldn't be
used until it gets debugged. So I'm thinking that the performance hit
of an exception might not be a problem here.

Here's a follow up question: How do you handle contract definition in
your abstract interface base classes? As I mentioned earlier in the
thread, this is a concern with respect to enforcing LSP. I'm eager to
know how folks handle that.

Thanks so much!

Ken
 
?

=?iso-8859-1?Q?Juli=E1n?= Albo

lilburne escribió:
Take another example: I have a polyline (think of it as a
vector of 3d points) which has the constraint that it has at
least 2 points, no two adjacent points are coincident, and
all the points are valid. Every method that takes a polyline
should check that the polyline it is given is valid. Testing
a polyline with a 100 points or more starts to become an
expensive operation, okay you may cache the result of a test

Don't use a vector. Make the polyline a class and check for validity
when constructing and when adding points.

Regards.
 
L

lilburne

Julián Albo said:
lilburne escribió:




Don't use a vector. Make the polyline a class and check for validity
when constructing and when adding points.

Well yes, but talking about some optimized container that we
built 10 years ago, obscures the issue when people can
simple think of it as a std::vector which they are already
familiar with.

Besides although the points *are* checked when they are
added to the container, there is nothing that stops someone
adding or modifying a method to the class that bypasses
those validity checks.

Well actually there is ... there are all the methods that on
taking a polyline call its is_valid() method, and the unit
tests that check that the is_valid() method asserts when
called on a polyline that is invalid.
 
?

=?iso-8859-1?Q?Juli=E1n?= Albo

lilburne escribió:
Well yes, but talking about some optimized container that we
built 10 years ago, obscures the issue when people can
simple think of it as a std::vector which they are already
familiar with.

Besides although the points *are* checked when they are
added to the container, there is nothing that stops someone
adding or modifying a method to the class that bypasses
those validity checks.

Make the source ot the polyline class read only ;)
Well actually there is ... there are all the methods that on
taking a polyline call its is_valid() method, and the unit
tests that check that the is_valid() method asserts when
called on a polyline that is invalid.

Or you can automate this by using a polyline_ref class that when
constucted call is_valid on the polline it refers, and make all
functions take a polyline_ref as parameter.

Regards.
 
L

lilburne

Julián Albo said:
lilburne escribió:



Or you can automate this by using a polyline_ref class that when
constucted call is_valid on the polline it refers, and make all
functions take a polyline_ref as parameter.

You've got the idea, though there are issues with that
approach. However you do it, I think you'll agree you don't
want all these checks being performed in a customer release
build. That is why you'll use assertions rather than exceptions.
 
?

=?iso-8859-1?Q?Juli=E1n?= Albo

lilburne escribió:
You've got the idea, though there are issues with that
approach. However you do it, I think you'll agree you don't
want all these checks being performed in a customer release
build. That is why you'll use assertions rather than exceptions.

The check made in all methods that takes a polyline argument yes, the
check done in a polyline constructions probably will be in the release
build and throw exceptions, if the construction is done with data
obtained from user interaction. That way the debug checks verifies that
the polyline class is valid and the other grants that no invalid
polyline object is used. Supossing, naturally, that a polyline
construction is done much less frequently that his use.

Regards.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top