[comp.object] Redefining

johnson@cs.uiuc.EDU (Ralph Johnson) (11/18/90)

In article <1990Nov16.065609.15460@tukki.jyu.fi>, sakkinen@tukki.jyu.fi (Markku Sakkinen) writes:

|> In my opinion, inheriting only parts of superclass, say C,
|> into a subclass, say D, is a highly dubious idea even for this purpose.
|> One should rather have defined a fully-fledged class B containing
|> those parts first, then both C and D as subclasses of B.
|> It would be nice to have the kind of generalisation facilities
|> that Claus Pedersen suggested in his OOPSLA'89 paper:
|> that one could derive _super_classes approximately as easily
|> as existing languages allow us to derive _sub_classes.


Before I start agreeing with Markku (which is always boring) let me
disagree a little.  When you are prototyping, you often care more about
the behavior of a program than its structure.  Thus, prototypers want
to get something working quickly, and don't care what it looks like.

However, the kind of program resulting from prototyping this way should
never be mistaken for elegant programs.  I rewrite code that results
from prototyping to make it elegant, and the rewriting often splits up
classes just the way Markku says.

I think that the conflict between getting something to work quickly and
making it elegant could be lessened with better programming environment
support.  We need tools that would split up classes and derive new
super classes from exisiting classes.

Following the Scandianvian tradition, a program provides a model of
some system.  When you find that you need to reuse just part of a class
then it means that your model was wrong.  Instead of patching up the
code, you should fix your model.

Sometimes people argue against this point of view by saying that
it isn't possible to revise the class hierarchy because the source
code is not available, or they will say that this is going against
reusable software because instead of reusing a class we are revising
a class.  Naturally, I disagree strongly with these points of view.
The first point is just a good reason why source should always be
avaliable, and the second shows that wrong definitions of software
reuse are being applied.  If you believe that the main purpose of a
program is as a model of a system, and that it is just as important
for a program to be a way of communicating between people as it is
for it to be a way of communicating with machines, then changing the
model is absolutely necessary when it is shown to be inadequate.

Ralph Johnson -- University of Illinois at Urbana-Champaign

brucec@phoebus.labs.tek.com (Bruce Cohen;;50-662;LP=A;) (11/20/90)

> In article <1990Nov16.065609.15460@tukki.jyu.fi>, sakkinen@tukki.jyu.fi (Markku Sakkinen) writes:
> 
> In my opinion, inheriting only parts of superclass, say C,
> into a subclass, say D, is a highly dubious idea even for this purpose.
> One should rather have defined a fully-fledged class B containing
> those parts first, then both C and D as subclasses of B.
> It would be nice to have the kind of generalisation facilities
> that Claus Pedersen suggested in his OOPSLA'89 paper:
> that one could derive _super_classes approximately as easily
> as existing languages allow us to derive _sub_classes.
> 
and in article <1990Nov17.174653.6291@ux1.cso.uiuc.edu> johnson@cs.uiuc.EDU (Ralph Johnson) writes:
> 
> However, the kind of program resulting from prototyping this way should
> never be mistaken for elegant programs.  I rewrite code that results
> from prototyping to make it elegant, and the rewriting often splits up
> classes just the way Markku says.
> 

I've recently started looking at dealing with this problem with what I call
"behaviours", which are lightweight abstract classes which each incorporate
the interface to one responsibility for its subclasses.  Behaviours are
completely disjoint in terms of interface and implementation; they may be
composed into cooperating sets of behaviours, but they may not share parts
of their interfaces or implementations.  A given subclass will inherit from
as many behavior superclasses as necessary for all of its responsibilities,
in mixin style.  No subclass may refuse to inherit a part of one of its
superclasses (with careful design of the superclasses, there aren't any
parts to object to; you either want the whole class or none of it).

This style makes it easy to factor inheritance so that everything needed by
a subclass is there, but the subclass doesn't get weighed down with things
it doesn't need.  It also makes it easy to rearrange inheritance without
major surgery on a program; since the concrete subclasses largely consist
of compositions of behaviours, most changes are a matter of altering the
composition and removing or adding the private methods which connect the
behaviors in the subclass.

> I think that the conflict between getting something to work quickly and
> making it elegant could be lessened with better programming environment
> support.  We need tools that would split up classes and derive new
> super classes from exisiting classes.

Tools like that would certainly be useful, especially in the case Ralph
cites of trying to clean up a bloated prototype.  I would like even more
to have tools which allow me to build the original version in a more
cleanly way, so I don't have to spend so much time cleaning up a program which
already works.  

> Following the Scandianvian tradition, a program provides a model of
> some system.  When you find that you need to reuse just part of a class
> then it means that your model was wrong.  Instead of patching up the
> code, you should fix your model.

I favor making the unit of reuse very small.  The smaller it is,
the less of the reused object (class, code, or design) is likely to be
unneeded in the reusing software.  That's why I think the unit should be a
part of a class; we just need to use tools which that convenient, and which
don't encourage us to muddy the inheritance structure by ad hoc, and in
a sense ex post facto, changes to the structure the is inherited.
--
------------------------------------------------------------------------
Speaker-to-managers, aka
Bruce Cohen, Computer Research Lab        email: brucec@tekchips.labs.tek.com
Tektronix Laboratories, Tektronix, Inc.                phone: (503)627-5241
M/S 50-662, P.O. Box 500, Beaverton, OR  97077

wdavis@x102c.harris-atd.com (davis william 26373) (11/21/90)

In article <1990Nov17.174653.6291@ux1.cso.uiuc.edu> johnson@cs.uiuc.EDU (Ralph Johnson) writes:
>
>Following the Scandianvian tradition, a program provides a model of
>some system.  When you find that you need to reuse just part of a class
>then it means that your model was wrong.  Instead of patching up the
>code, you should fix your model.

I do not agree that "the model was wrong".  After you find that you
"want to reuse" part of a class (not "need to resue" - there are always
alternatives), how does that make what went before "wrong".  Does
the program you want to reuse parts of no longer work?  Does it
fail to perform its function in some way, now that you want to reuse
part of it?  If I have a single linked list implementation and find
that I want to reuse parts of it (the link manipulation parts) in
a double linked list, how does that make it any less "right" as a
single linked list?

If you find that the original model "was wrong" it must be because
the model "was" not correct for the original problem or "is" not
correct for what the original problem is now known to be.  If you
find the original model "is not correct for a new problem", then
that is a different matter.

In terms of software reuse, the "is vs. was" of "model wrong" is
important because it determines what portions are to be reused
and what portions can be easily reused.

How does one draw the line between "new problem" and "new
understanding of old problem"?  I think that is the heart of
the matter concerning ease of software reuse.

>
>Sometimes people argue against this point of view by saying that
>it isn't possible to revise the class hierarchy because the source
>code is not available, or they will say that this is going against
>reusable software because instead of reusing a class we are revising
>a class.  Naturally, I disagree strongly with these points of view.

I disagree with the first because that is just a language specific
limitation.  In theory, why can't object modules come with sufficient
information to provide for "reuse".  Indeed, if an object module
can be used "only once", then how do we build multiple programs
from it.  Linking is only a small, albeit important, amount of reuse.
The linker question has been described sufficiently in other postings
but I have not seen a good solution proposed yet.  Is there one that
someone has already researched?

>The first point is just a good reason why source should always be
>avaliable, 

The first is also a good reason why more information is needed in
an object module.  Why should I be forced to go back to source
to reuse things?  Even when the source is available, why recompile?

>and the second shows that wrong definitions of software
>reuse are being applied.

I agree.

>  If you believe that the main purpose of a
>program is as a model of a system, and that it is just as important
>for a program to be a way of communicating between people as it is
>for it to be a way of communicating with machines, then changing the
>model is absolutely necessary when it is shown to be inadequate.

I agree the main purpose of a program is as a model of a system.
(Actually a program is a model of a design and a design is a
model of a system - different types of models).
But the program exists because the model serves some purpose (achieves
some result).  So, the reason for the model determines the detail
and biases in the model.  Thus, there can be two different models
of the same system for two different purposes.  Neither is inherently
right or wrong - the correct new of the model depends on the reason
for the model.

I agree it is important (maybe just as) for a program to be a
way of communicating between people.  But, as I have indicated
already, I do not agree that the model must be changed.  Indeed,
I would say a new model is necessary when a given model is shown
to be inadequate in a new domain.  Then there will be multiple
models in different domains.

I think the big question of reuse is:
  How does one build a model in a way that allows
  maximum reuse of the parts of the model?
This has large implications when you consider that a program
and a design are both models.

>
>Ralph Johnson -- University of Illinois at Urbana-Champaign

Bill Davis
Harris GISD
wdavis@x102c.ess.harris.com

Disclaimer: I am not an official.  So, these are not official views
of any person or entity.

johnson@m.cs.uiuc.edu (11/25/90)

I said:
>
>Following the Scandianvian tradition, a program provides a model of
>some system.  When you find that you need to reuse just part of a class
>then it means that your model was wrong.  Instead of patching up the
>code, you should fix your model.

Bill Davis (wdavis@x102c.ess.harris.com) said:
>I do not agree that "the model was wrong".  After you find that you
>"want to reuse" part of a class (not "need to resue" - there are always
>alternatives), how does that make what went before "wrong".  Does
>the program you want to reuse parts of no longer work?  Does it
>fail to perform its function in some way, now that you want to reuse
>part of it?

Most of the time when I am programming, I am trying to build reusable
software.  I am trying to describe an entire problem domain, and I
expect that the classes that I design will work for any problem in
that domain.  Thus, the model was wrong because it did not work for
a particular member of the domain.

A set of classes is like a scientific theory.  The individual programs
that you build out of these classes are the experiments that test the
theory.  If the programs require all sorts of weird work-arounds and
hacks to work then the theory starts to look like Ptolemaic astronomy
looks today.  Of course, Ptolemaic astronomy seemed pretty reasonable
to astronomers before Copernicus, and we often stick with an outmoded
set of classes.  Sometimes this is just because it is what we know.
Sometimes it is because we invented it.  Sometimes it is because we
have lots of code that uses it, and it would be too expensive to change.
As time goes on, we learn more and more about how we should have designed
the classes, and eventually it is worth the price to change.

A perfect example is Model/View/Controller.  It was the first user
interface framework, and every succeeding framework has owed a lot
to it.  However, it is now a decade old, and is definitely showing
its age.  Thus, version 4.0 of Smalltalk from ParcPlace has a new
version of Model/View/Controller that seems (from the little that
I have looked at it) to be a big improvement.  It should be easier
to learn, it should be easier to customize, and it should be easier
to use as a foundation for more reusable components.  On the other
hand, there is a cost to converting over, both to ParcPlace and to
their customers.

>If you find that the original model "was wrong" it must be because
>the model "was" not correct for the original problem or "is" not
>correct for what the original problem is now known to be.  

Usually the latter.  My understanding of a problem improves the
longer I work on it.  

Ralph Johnson -- University of Illinois at Urbana-Champaign