From: Nat Pryce Date: 2002-10-22T00:12:44+09:00 Subject: Re: Interfaces in Ruby On Sun, 2002-10-20 at 04:12, Jim Weirich wrote: > On Fri, 2002-10-18 at 14:08, Nat Pryce wrote: > > > [...] 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. -- Dr. Nathaniel Pryce, Technical Director, B13media Ltd. Studio 3a, 22-24 Highbury Grove, London N5 2EA, UK http://www.b13media.com