[comp.object] Deferred classes, overloading, genericity

pcg@cs.aber.ac.uk (Piercarlo Grandi) (11/24/90)

On 21 Nov 90 12:11:00 GMT, johnson@m.cs.uiuc.edu said:

johnson> pcg@cs.aber.ac.uk said:

pcg> Abstract (deferred) classes are no good of course. They are just a hack
pcg> to decouple a bit the algebra of interfaces from that of
pcg> implementations, which are otherwise coupled in inheritance.

johnson> I am shocked!  What can this mean?  Abstract classes are one of
johnson> the most important design techniques in object-oriented programming!

I am sorry to distress you, but I really meant that, literally. I agree
that they are one of the most important things in OO programming, but
only because OO programming as we know it now is very limited and
flawed. In other words, I don't believe that classes as we know them now
are OO programming's best friend (see the "is CLOS OO?" thread in
comp.lang.clos).

I will engage in restating my view of OO programming (I love to read my
own words! :->):

Assuming that we have a matrix indexed by type and operation, and whose
entries are implementations, OO programming is that style of programming
where it is assumed that _most often_ the best way to minimize inter
module dependencies and maximize reuse of interface, implementation, and
specification is to "cluster" (whatever that means...) implementations
by type rather than by operation.

This assumption is based on the idea that implementations of different
operations on the same type are more intimately related than those of
the same operation on different types.

In other words OO programming is based on *overloading*, either static
or dynamic (polymorphism). As a trivial example, real and complex
numbers have the same interface, but very different implementations
(and, in a way, specifications).  Using OO programming with static or
dynamic overloading means that the programmer can (statically or
dynamically) abstract programs syntaxes over the reals or the complexes,
without great effort.

Naturally this is *often* but not always true; for example if the types
are strongly related by specification, e.g. for all types whose
specification is a particular mathematical structure (hints of category
theory here...) then the implementations of the same operation for all
such types will often be strongly related.

This is a good reason for *genericity*, either static or dynamic. As a
trivial example, stacks and queues over any other type share much the
same specification (they are indeed both subsets of deques), and thus
the implementations of 'push' and 'pop' will be written identically for
all subtypes of stack, and they will be almost identical to those for
'next' and 'first' for a queue.

Traditional OO technology is forever torn (see the discussions in this
group) between overloading (abstraction on interface) and genericity
(abstraction on implementation), because there are languages like
Smalltalk in which the two are not spearated, and other like C++ where
they are not well separated.

johnson> Reading on, I decided that Piercarlo and I have different
johnson> definitions of abstract classes.  I think that he defines an
johnson> abstract class as one that has NO implementation, in which
johnson> every method is deferred.  However, my definition of an
johnson> abstract class is that it is a class that does not have a
johnson> COMPLETE definition, in which there is SOME method that is
johnson> deferred.

No, no, this is not my point. I accept that abstract classes can be not
just interface but also implementation templates. But I don't like them
being *both* -- I would like there there were different notations and
more orthogonal algebras for mix and match of interfaces and
implementations (and specifications). Deferred classes which are also
implementation templates are really about genericity, not overloading
like conventional classes are. Mixing the two technologies makes me
uneasy.

Indeed:

johnson> Abstract classes according to my definition are a crucial
johnson> technique for reusing classes.  An abstract class is a template
johnson> for its subclasses, and replaces other ways of reusing design
johnson> such as code skeletons.

Yes, as agreed above. But the point here is that (my usual party line)
one wants to abstract over types and functions along three dimaensions,
interface, implementation, specification. Non deferred classes allow for
reuse of interface and implementation on one type, with method
overloading; pure deferred classes allow reuse of interface decoupled
from that of implementation; a deferred class with methods is a way to
reuse interface and have generic implementations.

johnson> I agree with Piercarlo that abstract classes should not be used
johnson> just to represent types (though of course if you are
johnson> programming in C++ then you have no other choice).  Thus, we
johnson> probably don't really disagree.

Yes :-). Actually I also think that the problem is there also in
Smalltalk, where you also have really no other choice. Ther eis some
better hope in Self, Trellis, and CLOS (especially the latter, where you
can define any metaobject protocol).
--
Piercarlo Grandi                   | ARPA: pcg%uk.ac.aber.cs@nsfnet-relay.ac.uk
Dept of CS, UCW Aberystwyth        | UUCP: ...!mcsun!ukc!aber-cs!pcg
Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk