Path: utzoo!attcan!utgpu!news-server.csri.toronto.edu!mailrus!cs.utexas.edu!rutgers!ub!oswego!news From: dl@g.g.oswego.edu (Doug Lea) Newsgroups: comp.sw.components Subject: Re: OOP and re-usable cakes Message-ID: Date: 5 Aug 90 12:50:31 GMT References: <27705@athertn.Atherton.COM> <71800004@m.cs.uiuc.edu> <620@.tetrauk.UUCP> <7057.26b57e9c@swift.cs.tcd.ie> <707@tetrauk.UUCP> <382@taumet.com> Sender: news@oswego.Oswego.EDU (Network News) Reply-To: dl@g.oswego.edu Organization: SUNY Oswego Lines: 120 In-reply-to: steve@taumet.com's message of 4 Aug 90 21:07:56 GMT > From: steve@taumet.com (Stephen Clamage) > >rick@tetrauk.UUCP (Rick Jones) writes: > >This approach doesn't always reflect reality, though. You often do want an > >inheritance which says "A is like B except ...", meaning the sub-class is NOT > >going to conform to some aspects of its parent.... > > Again, you can do this in C++. It is possible to eliminate some of a > base (parent) class's functionality within a derived (sub) class. You > simply override the base class function in the derived class with an > empty function which is private. This is a TERRIBLE thing to do in any OOPL (like C++ and Eiffel) that attempts to maintain some relation between subclassing and subtyping. As Rick Jones says, it breaks conformance: If some base class Base contains some method m that returns an int, perhaps with some promises (postconditions) about the nature of the return value and/or the resulting state of the object, and a derived class Derived redefines m to simply abort execution or somesuch, then any polymorphic function accepting argument b of type Base or subclass thereof, and calls b.m may no longer be able to meet its own postconditions, since its implicit preconditions (i.e., that b is an object containing method m with specified behavior) are broken. Rick is right that programmers do often wish to create a new class B that is like some existing class A, except that it does not contain one or more methods/features. Probably the most common case of this is during the honorable activity of `retrospective abstraction', where you find that a class was overdesigned and you need something with fewer features; or that two previously unrelated classes could benefit by being linked via a new common ancestor. For among the simplest (perhaps least realistic) examples, suppose you HAVE a Deque class lying around, but you NEED a simple Stack class. The Deque contains methods push, pop, empty, rearpush, and rearpop. For both safety and coherence reasons, you don't want to just use the Deque as a Stack (since you want to guarantee that pushrear is NEVER called). But if you create class Stack as a subclass of Deque by nulling out rearpush and rearpop, you open up the Stack component to misuse: Sending a Stack to any function expecting a Deque might result in unexpected behavior like a core dump. In fact, it is easy to see that Stack is a SUPERclass of Deque. A Deque may be safely used wherever a Stack is expected. No `common' OOPLs allow you to RETROSPECTIVELY state this in any way short of redesigning the heirarchy. However, support for such constructs is not a completely novel idea: Retrospective superclassing is nearly the same notion as `views' in OBJ (see any of Goguen's recent papers) and LILEANNA (an Ada tool/preprocessor described by W. Tracz in his in-progress thesis) and `reductions' in Alberich (see July '90 SIGPLAN notices article by Paaki et al). It is also possible to get this effect in languages based on implicit conformance-checking rather than explicit subtyping/subclassing, e.g., Quest (see Cardelli's DEC-SRC TRs), and to some extent, Emerald/Jade (see Raj & Levy's ECOOP '89 paper). What might an OOPL supporting `views' (I'll stick to that term) look like? First, and most importantly, it MUST allow (even nicer: mandate) the separation of type specification (i.e., declaration of method argument and return types, perhaps with pre- and post-conditions) from class implementation (i.e., member data and code needed to carry out these specs). It is possible to maintain this separation via the convention of using `Abstract' or `Deferred' classes in C++, Eiffel, and other languages, or via more direct support found in Johnson's Typed Smalltalk (TS) and Emerald. This separation is necessary in order to ensure that a new view is properly self-contained. For example, if the Deque class, above, mixed specification and implementation, it might be the case that Deque::push was implemented by calling Deque::rearpush when the Deque is empty. A Stack view of the Deque that omits rearpush would then fail to even make sense. The consensus these days seems to be that such separation is a Good Thing anyway: it allows specifications to be realized via multiple implementations with different performance characteristics; it allows independent reuse of either specifications or implementations; and allows independent extensions of both types and implementations. However, separation of specification and implementation can make it hard to reuse implementations without further aids. A composition mechanism similar to that of Emerald/Jade that is equally useful for both composing and splitting apart implementations would be a valuable adjunct. Alternatively, the implementation side might even employ a form of prototyping/delegation (as in SELF) instead of subclassing or composition: Separating specifications from implementations allows the design and coding tools/constructs to vary independently. There are a number of other interesting issues as well. Among them: *) Renaming: Suppose the Deque method to place things on the front was called `frontpush', but you'd like it to be called just `push' in the Stack view. Is this OK? *) Multiple views: A Deque can be view'd as a Stack in either of two ways (using the Deque push/pop pair OR the rearpush/rearpop pair to perform Stack push/pop). Can more than one view be supported? *) Structure: Programs written with views might be hard to read since new superclasses can be declared on the fly. Tools are needed to reconstruct/fake the underlying hierarchical design. *) And a host of implementation matters ... Are views important enough constructs to warrant creation of new languages or tools? (All of the above COULD be incorporated into a front-end design tool/preprocessor for C++, Smalltalk, SELF or nearly any other OOPL.) -Doug -- Doug Lea, Computer Science Dept., SUNY Oswego, Oswego, NY, 13126 (315)341-2688 email: dl@g.oswego.edu or dl@cat.syr.edu UUCP :...cornell!devvax!oswego!dl or ...rutgers!sunybcs!oswego!dl