Topic: Design by Contract in C++?


Author: Kevlin Henney <kevlin@curbralan.com>
Date: Sun, 26 Aug 2001 17:27:46 GMT
Raw View
In article <i7k8BIAC8Vh7EwK2@jgharris.demon.co.uk>, John G Harris
<john@nospam.demon.co.uk> writes
>There are two particular problems with monitoring. First, invariants
>apply to every member function, but some are impractical to monitor. For
>instance, a list's size() value should be the same as you would get by
>counting from Begin() using an iterator, but checking this is an O(n)
>process.
>
>Second, destructors have an important job to do so this job should be
>described by a post condition. What should happen if the check fails but
>a system design rule says don't throw from destructors?

There is another, perhaps more significant issue: re-entrancy. In the
traditional DBC model, as proposed by Meyer in OOSC and as implemented
in monitored form in Eiffel, the invariants are checked with the pre and
postcondition of every public function. This covers many common cases,
but fails to account for inversion of control flow, a rather important
design style in many OO and event-driven systems, as well as the
interaction with threading.

To resolve this you either unask the question, saying that DBC
monitoring is applicable only for top-down control flow, or you extend
the DBC model to also include continuous invariants (eg "rely" and
"guarantee" in Catalysis complement pre and postconditions). The second
solution is something of a Pandora's box for realistic monitoring.

Kevlin
____________________________________________________________

  Kevlin Henney                   phone:  +44 117 942 2990
  mailto:kevlin@curbralan.com     mobile: +44 7801 073 508
  http://www.curbralan.com        fax:    +44 870 052 2289
  Curbralan: Consultancy + Training + Development + Review
____________________________________________________________

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Pete Becker <petebecker@acm.org>
Date: Mon, 27 Aug 2001 18:52:41 GMT
Raw View
John G Harris wrote:
>
> In article <3B8578EA.F44BF981@acm.org>, Pete Becker <petebecker@acm.org>
> writes
> >John G Harris wrote:
> >>
> >> There are two particular problems with monitoring. First, invariants
> >> apply to every member function, but some are impractical to monitor. For
> >> instance, a list's size() value should be the same as you would get by
> >> counting from Begin() using an iterator, but checking this is an O(n)
> >> process.
> >
> >Of course, that particular problem is solved by changing the invariant.
> >Adding an element produces a size that is one more than the size before
> >the add operation, etc.
>
> There are two ways this could be read.

There is a third, and it's that incremental checking can produce the
same results as full checking.

> Another reading is that we don't mind if a list's pointers are mangled
> because it's inconvenient to check that they haven't been. I don't buy
> that and I'm hoping no-one else does either.

Checking a list's integrity involves far more than counting elements.

--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: John Nagle <nagle@animats.com>
Date: Mon, 27 Aug 2001 15:18:47 CST
Raw View
Kevlin Henney wrote:
> There is another, perhaps more significant issue: re-entrancy.

    Yes.  You have to get serious about knowing whether control is
inside the class or not.

    Clearly, calling a public function from inside the class has
to be disallowed.  But you need more than that.  There's
still the possibility that a function of object A calls a function
of object B which calls a public function of object A.  You need
to detect such calls as errors.  This could be done at run time.

    Once the inside/outside distinction is enforced, you need
a way to temporarily "leave" an object.  I'd considered

 void classname::fn1()
 {    // executable code
      public { fn2() } ;  // call is "outside"
 }

Code within the "public" section is "outside" the class.  It
can't see private members, and the class invariant has to
be reestablished before entering the "public" section.

This ties in with locking.  If you have "synchronized"
classes, like Java, they're unlocked when entering a
"public" section.  This makes locking play well with
with design by contract.

If the next version of C++ comprehends threads and locking
(which it should), this is worth looking at again.
But I just can't see real design by contract flying in C++.

     John Nagle
     Animats

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: John G Harris <john@nospam.demon.co.uk>
Date: Sat, 25 Aug 2001 02:35:35 GMT
Raw View
In article <3B8578EA.F44BF981@acm.org>, Pete Becker <petebecker@acm.org>
writes
>John G Harris wrote:
>>
>> There are two particular problems with monitoring. First, invariants
>> apply to every member function, but some are impractical to monitor. For
>> instance, a list's size() value should be the same as you would get by
>> counting from Begin() using an iterator, but checking this is an O(n)
>> process.
>
>Of course, that particular problem is solved by changing the invariant.
>Adding an element produces a size that is one more than the size before
>the add operation, etc.

There are two ways this could be read. One reading is that the code
provides partial monitoring of the contract on the grounds that
something is better than nothing. I've no quarrel with that provided
people notice when monitoring is partial.

Another reading is that we don't mind if a list's pointers are mangled
because it's inconvenient to check that they haven't been. I don't buy
that and I'm hoping no-one else does either.

>> Second, destructors have an important job to do so this job should be
>> described by a post condition. What should happen if the check fails but
>> a system design rule says don't throw from destructors?
>>
>
>Throwing an exception is probably the wrong thing to do anyway. Abort
>with a message. There's nothing the application can do about a
>programming error.

Hm. Is this always the right thing to do? Can other parts of the system
remain untainted?

  John
--
John Harris
  mailto:john@jgharris.demon.co.uk

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Peter Nordlund L (QRA)" <Peter.L.Nordlund@era.ericsson.se>
Date: Mon, 20 Aug 2001 17:31:59 GMT
Raw View
Excuse me if this topic have been discussed lately.
I have scanned deja.com and I have not found anything
about design by contract with a recent date.


Questions:

1. Would it be possible to add design by contract to the C++ language?
2. Is there any interest in doing so?
3. Now if there is any interest, how should it be done?
    Direcly in the language with new keywords and stuff, or in some library-code.
4. Is someone out there aware of efforts to implement DBC for C++?
I know that there is some stuff done at
<http://www.cs.ntu.edu.au/homepages/pjm/nana-home/adfa/index.html>
and
<http://www.digitalmars.com/ctg/designbycontract.html>

At www.boost.org's <http://www.boost.org's> mailing list
in the "files" section
you find two assertion packages with some macros
for Eiffel-like DBC stuff. But I am not aware of which status
these packages have. As far as I could see there has not been
any discussion about DBC on the boost mailing list.


In the interview with Bjarne
<http://www.itworld.com/AppDev/710/lw-02-stroustrup/>
it seems like he is interested in improving the support
for assertions and the like in C++.


I guess that if an effort is made one, should be inspired by
the Eiffel language.


The Eiffel keywords
require, ensure, invariant, old
are probably the ones that should act as inspiration.


See <http://www.eiffel.com/doc/manuals/technology/contract/index.html>
for a more detailed description of the Eiffel code example below.

class interface DICTIONARY [ELEMENT] feature

put (x: ELEMENT; key: STRING) is
-- Insert x so that it will be retrievable
-- through key.
require
count <= capacity
not key.empty
ensure
has (x)
item (key) = x
count = old count + 1

... Interface specifications of other features ...

invariant

0 <= count
count <= capacity

end -- class interface DICTIONARY



Any thoughts or comments?


Best regards,
Peter Nordlund


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: John Nagle <nagle@animats.com>
Date: Wed, 22 Aug 2001 05:26:19 GMT
Raw View
    As someone who was doing proof of correctness work long before
Eiffel, I'd like to work in a language with enforceable interface
contracts.  But it's not going to happen in C++.  C++ isn't
rigorous enough, and its users don't want it rigorous.
I regard this as sad, but accept it.

     John Nagle
     Animats

"Peter Nordlund L (QRA)" wrote:
> Excuse me if this topic have been discussed lately.
> I have scanned deja.com and I have not found anything
> about design by contract with a recent date.
>
> Questions:
>
> 1. Would it be possible to add design by contract to the C++ language?
> 2. Is there any interest in doing so?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Noah Stein" <noah@vision-scape.com>
Date: Wed, 22 Aug 2001 23:43:11 GMT
Raw View
"Peter Nordlund L (QRA)" <Peter.L.Nordlund@era.ericsson.se> wrote in message
news:BFB4240871E8D411B3FC00508BCF8EAA8CD80C@esealnt453.al.sw.ericsson.se...
> Excuse me if this topic have been discussed lately.
> I have scanned deja.com and I have not found anything
> about design by contract with a recent date.
>
>
> Questions:
>
> 1. Would it be possible to add design by contract to the C++ language?
> 2. Is there any interest in doing so?
> 3. Now if there is any interest, how should it be done?
>     Direcly in the language with new keywords and stuff, or in some
library-code.
> 4. Is someone out there aware of efforts to implement DBC for C++?
> I know that there is some stuff done at
> <http://www.cs.ntu.edu.au/homepages/pjm/nana-home/adfa/index.html>
> and
> <http://www.digitalmars.com/ctg/designbycontract.html>

I'm currently playing with design by contract schemes under C++; however I
have only just started playing around with the issues, so I don't really
have much to add.  I'm mostly focusing on DBC as it pertains to generic
programming.  I'm sorry I can't give you any insight right now, but I
thought you might be interested in the fact that, yes, others are interested
in the topic, too.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: John G Harris <john@nospam.demon.co.uk>
Date: Thu, 23 Aug 2001 21:33:39 GMT
Raw View
In article <BFB4240871E8D411B3FC00508BCF8EAA8CD80C@esealnt453.al.sw.eric
sson.se>, Peter Nordlund L (QRA) <Peter.L.Nordlund@era.ericsson.se>
writes
  <snip>
>1. Would it be possible to add design by contract to the C++ language?
>2. Is there any interest in doing so?
>3. Now if there is any interest, how should it be done?
>    Direcly in the language with new keywords and stuff, or in some library-
>code.
  <snip>

Design by Contract is mainly about human beings saying what they mean
and meaning what they say. I think your concern is the monitoring of DbC
in the code.

If you don't mind a remnant of your monitoring overheads in the release
version of the program then I believe you can do it in C++ without
needing new keywords.

If not, you need conditional compilation and hence a keyword to avoid
the use of macros. Sounds like another overload of "virtual" :-)

There are two particular problems with monitoring. First, invariants
apply to every member function, but some are impractical to monitor. For
instance, a list's size() value should be the same as you would get by
counting from Begin() using an iterator, but checking this is an O(n)
process.

Second, destructors have an important job to do so this job should be
described by a post condition. What should happen if the check fails but
a system design rule says don't throw from destructors?

  John
--
John Harris
  mailto:john@jgharris.demon.co.uk

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Pete Becker <petebecker@acm.org>
Date: Thu, 23 Aug 2001 21:48:02 GMT
Raw View
John G Harris wrote:
>
> There are two particular problems with monitoring. First, invariants
> apply to every member function, but some are impractical to monitor. For
> instance, a list's size() value should be the same as you would get by
> counting from Begin() using an iterator, but checking this is an O(n)
> process.

Of course, that particular problem is solved by changing the invariant.
Adding an element produces a size that is one more than the size before
the add operation, etc.

>
> Second, destructors have an important job to do so this job should be
> described by a post condition. What should happen if the check fails but
> a system design rule says don't throw from destructors?
>

Throwing an exception is probably the wrong thing to do anyway. Abort
with a message. There's nothing the application can do about a
programming error.

--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]