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