[…] Also, in my experience, DbC ends up polluting the class
interface with a lot of predicates, because it doesn’t support the idea
of protocols, […]
I’m not sure I understand the above comment.
Often, when designing classes you define a protocol by which calls can
be made to the object. A simple example, a Socket object has methods to
connect, read and write data, shutdown the read or write stream, or
close both streams. You must call connect before calling read, write,
shutdown or close. Once you’ve called close, you cannot call read or
write again until you call connect again. Once you’ve shutdown the read
stream you cannot read, and similarly for write shutdown.
Client code that uses a socket keeps track of the socket state by its
own control flow. A socket can only be in a closed state if it has been
closed by the client code (ignoring errors in this example).
However, to specify this protocol in DbC you have to define
preconditions on whether the socket is open, and those preconditions
have to be defined in terms of public methods. E.g. the read method
might be:
read : BYTE is
-- read a byte from the stream
require
is_open_for_read
do
-- blah blah blah
ensure
(is_open_for_read and result >= 0 and result < 255) or
(not is_open_for_read and result == -1)
end
is_open_for_read : BOOLEAN
– a predicate that tests whether the stream is open
– for reading
So you end up adding predicates to the public API of objects to track
the progress of the protocols used to interact with those object. Often
this also requires adding data members to keep track of the current
state of the object.
[…] and makes changing code very difficult because contracts
are duplicated throughout the code.
Really? In my experience, the contract normally gets specified in the
most abstract class, and there is little need to repeat it. Subclasses
only express modifications and refinements to the contracts they
inherit.
I found that when writing code that had a lot of composition, rather
than inheritance, contracts of classes would end up mirrored in the
interface of other classes that contained them, and in containers of
containers, and so on. If you changed the contract of a component
class, then the change would ripple through the containers. In very
compositional code, it became quite expensive to change contracts.
Cheers,
Nat.
···
On Sun, 2002-10-20 at 04:12, Jim Weirich wrote:
On Fri, 2002-10-18 at 14:08, Nat Pryce wrote:
–
Dr. Nathaniel Pryce, Technical Director, B13media Ltd.
Studio 3a, 22-24 Highbury Grove, London N5 2EA, UK
http://www.b13media.com