Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

interface reuse over code reuse

1 view
Skip to first unread message

Steven D. Majewski

unread,
Nov 3, 1993, 9:27:18 PM11/3/93
to
Henry Spencer <he...@zoo.toronto.edu> wrote:
>Indeed, there are a significant number of people who think that once you
>strip away the OOH (Object-Oriented Hype), being able to reuse
>*interfaces* is much more important than being able to reuse code. If the
>interface is held constant, you can build up a library of different
>implementations of the underlying abstraction to satisfy different sets of
>tradeoffs.

From my recent experience with using classes in Python, I would agree with
that statement. Python is an OO language that is "objects all the way
down", but the builtin objects are not part of the class system. Thus,
you can use (multiple) inheritance with user defined classes, but you
can't inherit methods from builtin objects like files, integers, lists,
strings, etc. What you can do, though, is to emulate the interface of
builtin objects by defining the appropriate methods in your class.

For example, if you define methods for all of the standard numeric
operations, you can create new numeric types. If you define methods for
len, getitem, getslice you have something that behaves like a sequence,
and if you add setitem and setslice it becomes a mutable sequence.

So I've had occasion to use both inheritance and a sort of abstract data
typing in Python. Inheritance is *nice* - it avoids a lot of cutting and
pasting in the editor - but the big gain (IMHO) seems to be from reusing
the interface - not necessarily the code.

[ And isn't that one of the secrets of the power of Unix - that it
makes a lot of different things act just like a sequential file? ]


The only problems appear to be:
(1) Keeping that consistency when you aren't using inheritance to
enforce it. [ I've been arguing against some inconsistencies
on the python-list, for example, that
array.write( file, count ) is different enough from
[file|pipe|socket].write( count ) that it would be better
called by a different name. ]
(2) In a dynamic/interpreted language like Python, you have to pretty
much give up on (dynamic) type checking as overly restrictive.
You don't really want to know if two objects share a common base
class - what you really want to know is if it is going to behave
the way you expect a (number|sequence|file|some-other-type) to
behave. Avoiding type-checking seems to allow you to discover
unexpected treats, for example, that it's possible to create
complex numbers composed of rational parts. [ There was a long
thread on comp.object about heterogeneous containers that
verged into this area just around the time I we were discussing
the pros and cons of typechecking on the python-list. I had been
proposing adding standard boolean methods like "isnumeric" and
"isasequence" to make it possible to check the type of arguments
without being overly exclusive, but I have given up on that for
now. It seems if you are going to trust another class programmer
to have defined those booleans to behave properly, you might as
well go all the way and trust that if the class has a method
defined for __add__, then you should (provisionally) assume that
it works the way you expect it to work. One counter example to
isnumeric was a date class. It might support offsets to a date,
or subtracting two dates, but not multiplying or dividing, So
should it claim to be numeric ? ]

Sorry about the rambling nature towards the end. I should have gone
home a couple of hours ago. I'm going to print out David Keppel's
paper and go home now.


- Steve Majewski (804-982-0831) <sd...@Virginia.EDU>
- UVA Department of Molecular Physiology and Biological Physics
--
Send compilers articles to comp...@iecc.com or
{ima | spdcc | world}!iecc!compilers. Meta-mail to compiler...@iecc.com.

Mark C. Carroll

unread,
Nov 8, 1993, 5:03:58 PM11/8/93
to
Henry Spencer <he...@zoo.toronto.edu> wrote:
>Indeed, there are a significant number of people who think that once you
>strip away the OOH (Object-Oriented Hype), being able to reuse
>*interfaces* is much more important than being able to reuse code. If the
>interface is held constant, you can build up a library of different
>implementations of the underlying abstraction to satisfy different sets of
>tradeoffs.

Steven D. Majewski <sd...@elvis.med.virginia.edu> writes:
>From my recent experience with using classes in Python, I would agree with
>that statement. Python is an OO language that is "objects all the way
>down", but the builtin objects are not part of the class system.

This is a little off thread, but it does point out a very common mistake
made in discussions of things object-oriented.

To say that "X is an OO language with objects all the way down" *means*
that in X, everything is an object. If X has a class system, then
*everything* is in the class system. To say that "X is an OO language with
objects all the way down, but the builtin objects are not part of the
class system" is much like saying "Y is a completely side effect free
language, except for the assignment statements."

... Thus,


>you can use (multiple) inheritance with user defined classes, but you
>can't inherit methods from builtin objects like files, integers, lists,
>strings, etc. What you can do, though, is to emulate the interface of
>builtin objects by defining the appropriate methods in your class.

...


>For example, if you define methods for all of the standard numeric
>operations, you can create new numeric types. If you define methods for
>len, getitem, getslice you have something that behaves like a sequence,
>and if you add setitem and setslice it becomes a mutable sequence.

In Sather 1.0, a new object-oriented language, you can do similar things,
by taking advantage of its two-part inheritance system. The idea is that
there are really two different kinds of inheritance - inheritance of
interface, and inheritance of implementation. In Sather, those two have
been separated into two different constructs in the language.

If you have a type that you want to use as a mutable sequence, you have it
inherit interface from the abstract type $MUTABLE_SEQUENCE, and then
provide implementations for all of the operations that work on a mutable
sequence:

class NewSequence < $MutableSequence is
int getitem ...
...
end -- NewSequence

In this case, you don't get any implementations that went with
NewSequence.

Alternately, you can reuse implementations by using implementation
inheritance, but without necessarily inheriting interface. So, for
example, you may want to implement a stack using the concrete
implementation of lists as a base. But a stack doesn't implement list
operations. So, you'd use implementation inheritance without interface
inheritance:

class Stack{T} is
include CONCRETE_LIST{T}
push(x:T) is ... end
pop:T is ... end
end -- Stack{T}

And, of course, you can inherit interface AND implementation by using both
inherit forms.

When I first read about this separation, I was very hesitant to accept the
intelligence of it. But on further consideration, especially in light of
the discussion here, it seems to look better and better.

It seems far better to provide something like this, which allows the use
of interfaces for static type-checking, but while also allowing the
programmer to disregard the internal structure and implementations of it
parent classes, is *far* more useful than the more restricted kind of
inheritance that has come before, and also preferable to the
Python/Objective-C kind of inheritance where similar effects are possible,
but without static type checking.

Anyone interested in Sather based on this should take a look at
comp.lang.sather, or at the language spec on icsi.berkelet.edu:pub/sather

<MC>
--
Mark Craig Carroll: <MC>
CIS Grad, Univ of Delaware
car...@udel.edu

0 new messages