[comp.lang.smalltalk] Use of inheritance for classification?

kmcentee@Apple.COM (Kevin McEntee) (05/13/89)

Meyer's Object Oriented Software Construction recommends that subclassing
should take place only in the context of the is-a relationship.

    e.g.  Every dog is a mammal.

This seems to imply that inheritance is first a classification scheme and 
only second a code sharing mechanism.  

What are your thoughts on this?  Can code sharing outside of the natural 
taxonomy of the problem space happen gracefully?

Thanks,
	Kevin McEntee   
	kmcentee@apple.com

bpe@brunix (Page Elmore) (05/14/89)

I do not think that inheritence is ever classification: it is specialization.
This misconception will cause you lots of trouble when you attempt to define
a class hierarchy. Classification implies something like:

	Type Car
		color:Red, Blue, Grey, Black, White, etc.
	   |
	   |
	   |
	Type Honda CRX (inherits from Car)
		color: Red, Black

Thus you attempt to constrain the value class of the color attribute, causing
no end of trouble code which attempts to use a Honda CRX in place of a Car.

Page Elmore

riks@csl.sony.JUNET (Rik Smoody) (05/15/89)

In article <30582@apple.Apple.COM> kmcentee@Apple.COM (Kevin McEntee) writes:
>should take place only in the context of the is-a relationship.
>
>    e.g.  Every dog is a mammal.
But not all dogs are frisbeeCatchers. 
Do I need a special sub-class?
Most dogs who catch frisbees use their mouth.
Do we need special code for each dog or class who is to learn that trick?
How would the subclasses by abilities combine with the subclasses
such as Collie, AustralianShepherd, Spotted, LongHaired, FinickyEater,
MailManBiting, etc.
Soon, I might have an inordinately large set of classes, with such
taxonomic gems as 
Every
BurglarBarkingFrisbeeFetchingBlackAndWhiteLongHairedOmnivorousAustralianShepherdDog
is-a  FrisbeeFetchingBlackAndWhiteLongHairedOmnivorousAustralianShepherdDog
	(only slightly more sightly if I don't make the artificial
	restriction to single-inheritance)
>
>This seems to imply that inheritance is first a classification scheme and 
>only second a code sharing mechanism.  
The hard part about code sharing is knowing when.  That's true for
objects which belong to classes, and for procedures which get called
from different places with different arguments Fortran or C.
There's a baby in that bath-water.
Where does the "code" of tieShoeLaces get attached to the taxonomy of
humans?  (Oops... can't  a monkey learn how to tie shoes?  Two sparrows
in a Disney cartoon?)  Most of us do it the same way.  A good candidate
for code sharing.

>
>What are your thoughts on this?  Can code sharing outside of the natural 
>taxonomy of the problem space happen gracefully?
Don't blindly assume a natural taxonomy, even in nature.
Many great minds have argued inconclusively on the natural
taxonomy of biological systems.  Since we in CS are not bound by such
constraints as species development by evolution, it seems a long reach
to assert that any one taxonomy is comprehensive.

Taxonomizing (is that a word?) and Code Sharing are not equivalent.
We all have a blood type.  That's a taxonomy.  Exposure to certain
diseases is another taxonomy.  Profession is another.  People of
almost any profession (not the oldest), who do not possess any of the
forbidden risk factors, should all share the code and give blood
now and then.

"Most generalizations are pretty good"

Rik Fischer Smoody
Sony Computer Science Lab, Inc.
3-14-13 Higashigotanda, Shinagawa-ku	
Tokyo 141 Japan

phone: (03)448-4380
E-mail: riks@csl.sony.jp
or maybe: riks@csl.sony.co.jp
-- 
Rik Fischer Smoody
Sony Computer Science Lab, Inc.,  3-14-13 Higashigotanda
Shinagawa-ku, Tokyo 141 Japan
(03)448-4380

kain@object.UUCP (Kai Ng) (05/16/89)

In article <30582@apple.Apple.COM> kmcentee@Apple.COM (Kevin McEntee) writes:
>
>Meyer's Object Oriented Software Construction recommends that subclassing
>should take place only in the context of the is-a relationship.
>
>    e.g.  Every dog is a mammal.
>
>This seems to imply that inheritance is first a classification scheme and 
>only second a code sharing mechanism.  
>
>What are your thoughts on this?  Can code sharing outside of the natural 
>taxonomy of the problem space happen gracefully?
>

Dr. Meyer's "is-a" rule provides an easy to understand rule of thumb for
subclassing. Since object oriented programming has only emerged, even in
the academic world, for a relatively short period of time, programmers at
large in the production world are admittedly not well prepared to take on
such paradigm. That is the reason why the questions like

    "When should I subclass ?"
    "From which class I should inherit from ?"
    "Is it appropriate to add such a feature (method) to the heir class(es) ?"
    "Is it worthy to introduce a deferred (abstract) class in between ?"
    ....

are heard many many times over.

An important advantage of OOP, other than the familiar facilitating code
re-use, is good understandability which is achieved via some OOP conventions
and practices such as good naming, peronalizing (objectizing) objects and
rules like "is-a", etc. Although it is arguable whether integrating common
sense, like a dog is a mammal, with inheritance structure has too much
restriction or not, it is not questionable with the aid of such kind of
common sense, the characteristics of an object can be perceived better.

It is not uncommon programmers do not trust each other's code; and the
severity tends to be exponential inversely proportional to the degree
they understand the code. Hence don't feel supprised if you find a Car
object is more than 4-wheel drive.

My point is understandability encourages code re-use. Removing the natural
taxonomy inevitably, I believe, will remove the power of common sense.
You can draw your own conclusion then.

Even if you view inheritance as a classification scheme is not bad; most
software libraries classify various modules in some manner anyway.

Although I feel using the concept of generalization v.s. specialization
is a more suitable rule for subclassing, I always attempt not to break the
"is-a" rule.

The "is-a" rule is almost perfect in any single inheritance environment,
nevertheless it does has its short falls in a true mulitple inheritance
environment like Eiffel. The case is worse on the hand of a good OO programmer
who always manage to re-use more classes, i.e. inherit from more classes at
once. The problem is self-explained in the following example.

    CLASS SmallInteger
        -- General purpose small integer.

    INHERIT
        MachineConstants;
        Number

    ...
    END -- Class SmallInteger

The "is-a" rule is ok with Number-SmallInteger whereas it is not appliable
at all for MachineConstants-SmallInteger. In our group, we introduce a
keyword in the form of comment to clarify this.

    INHERIT
        -- Use --
        MachineConstants;

        -- Inherit --
        Number
    ...

If the inheritance status is USE, no feature is allowed to be exported.
It would be nice if USE is a real Eiffel keyword and exporting is enforced
by the compiler itself.







-- 
Kai Ng                 P.O. Box 9707         UUCP: uunet!mitel!sce!cognos!kain
Cognos Incorporated    3755 Riverside Dr.
(613) 738-1440         Ottawa, Ontario,
 ext. 6114             CANADA  K1G 3Z4

dld@F.GP.CS.CMU.EDU (David Detlefs) (05/16/89)

Page Elmore writes --

>I do not think that inheritence is ever classification: it is specialization.
>This misconception will cause you lots of trouble when you attempt to define
>a class hierarchy. Classification implies something like:
>
>	Type Car
>		color:Red, Blue, Grey, Black, White, etc.
>	   |
>	   |
>	   |
>	Type Honda CRX (inherits from Car)
>		color: Red, Black

>Thus you attempt to constrain the value class of the color attribute, causing
>no end of trouble code which attempts to use a Honda CRX in place of a Car.

If this is classification, what is it that you think of as
specialization?  Whatever you call it, I think this is exactly the
kind of use of inheritance that Meyer and Liskov, among others
recommend.  I don't see where the fact that the set of colors that a
Car may be is larger than the set of colors supported by HondaCRX.  To
make this work properly, you would only be allowed to specify the
color of a Car at the time of creation.  If you created a more
specialized (or "classified" -- I really don't understand your terms)
Car like a HondaCRX, it's creation function would constrain the set of
acceptable colors.  After creation, HondaCRX should fulfil Car's
specifications of each of it's operations.

I really think this works out fine, and is the right way to use
inheritance.  Meyer's book and Liskov's article in OOPSLA (87? 88?)
make this point persuasively.



--
Dave Detlefs			Any correlation between my employer's opinion
Carnegie-Mellon CS		and my own is statistical rather than causal,
dld@cs.cmu.edu			except in those cases where I have helped to
				form my employer's opinion.  (Null disclaimer.)
-- 

plogan@mntgfx.mentor.com (Patrick Logan) (05/17/89)

In article <30582@apple.Apple.COM> kmcentee@Apple.COM (Kevin McEntee) asks:
=?   Can code sharing outside of the natural taxonomy of the problem
=? space happen gracefully?

Here are some thoughts, written humbly as a would-be OO programmer not
as an expert sage. (Just in case it comes across that way.)

Perhaps in "Object Oriented Programming" there is no difference
between code sharing and classes sharing a common class. In languages
that are nearly "pure" OOLs (e.g. Smalltalk, Eiffel) it seems there is
no way to share code without specifying the sharing as a common super
class.

Is there a reason to share code some other way? In hybrid OOLs such as
CLOS and C++ it's possible to revert to creating good old procedures.
What would be a reasonable situation to do so? I usually think of
doing so in order to create a local procedure as a part of
implementing a particular method. Or to be shared between methods of a
particular class. If I was sharing a procedure in methods of disparate
classes I would probably look for a missing link in the class
taxonomy.

Also, there's an article* that suggests an "algorithm" should in some
cases be considered an object, e.g. FFTs. So one could create a class
for a particular procedure or group of procedures that may not usually
be considered objects. These would probably be few and far between.



* "Using Types and Inheritance in Object Oriented Programming",
  Halbert, Daniel C. and Patrick O'Brien, (both at DEC)
  IEEE Software, Sept. 1987

-- 
Patrick Logan                | ...!{decwrl,sequent,tessi}!mntgfx!plogan 
Mentor Graphics Corporation  | plogan@pdx.MENTOR.COM                    
Beaverton, Oregon            | "My other computer is a Lisp machine."

kentb@Apple.COM (Kent Beck) (05/17/89)

I think the confusion over this issues arises from the inheritance hierarchy
being used for two purposes- classification sharing and code sharing.  If I
have only one hierarchy to work with (as in Smalltalk) I use it to share
code ONLY, but I'd really rather have two hierarchies.

Kent

jwd@ihlpl.ATT.COM (Davison) (05/17/89)

In article <30582@apple.Apple.COM> kmcentee@Apple.COM (Kevin McEntee) writes:
>
>Meyer's Object Oriented Software Construction recommends that subclassing
>should take place only in the context of the is-a relationship.
>
>    e.g.  Every dog is a mammal.
>
>This seems to imply that inheritance is first a classification scheme and 
>only second a code sharing mechanism.  
>
>What are your thoughts on this?  Can code sharing outside of the natural 
>taxonomy of the problem space happen gracefully?
>                                     ^^^^^^^^^^

I'm glad you added that last word.  It seems to me there are
several non-taxonomic reasons one might use inheritance for
particular methods, but inheriting all methods from a class seems
to imply some sort of strong relationship between the classes.  If
not "is-a" perhaps "acts-like-a" or "impersonates."  I feel the
inheritance structures ought to have an epistemological basis of
some kind.  It seems to me that the work done in knowlege
representation systems is directly applicable to many questions
like this.  I recommend Ron Brachman's paper "I lied about the
Trees", AI Magazine, Vol 6, No 3, Fall, 1985, for instance.
Constantine's/Yourdon's ideas on coupling/cohesion in Structured
Design (Prentice Hall, 1979) also seems relevant, as do database
normalization ideas.

Inheritance for individual methods is often desired because there
is "one" thing that needs to be done, and it should be only
specified once, but it really doesn't "belong" at the point in the
inheritance chain where it has to be to be accessible to all
concerned classes.  In this case, delegation seems to be a better
solution, an instance variable holds an object of the "appropriate"
class, (the one that "ought" to own the method), and a local method
simply passes the message to that object. 

Perhaps multiple inheritance can provide an out, where one
inheritance path is "is-a" while another represents some other
relationship.  

The "gracefulness" seems to rely on something a bit stronger than
"coincidental coupling".

-- 
		Joe Davison
		ihlts!joed 
		IH 6N-424  x4920

bpe@brunix (Page Elmore) (05/18/89)

If you have the types such as:

       Type Car
          ^    Property: color: allColors (type with instances of all colors)
          |    Method:   Paint(newColor: allColors)
          |
          |
       Type Honda CRX (inherits from Car)
               Property color: blueBlack (type with blue and black instances)


where Type Car defines a property color which has as it's value type allColors
and also has a method Paint which takes as its argument an instance of
allcolors. Somewhere in the implementation of paint it sets the color of
the car to the newly painted color -- an instance of allColors. Now
what happens when someone invokes the Paint method with red as the argument
on members of a set of Cars, some of which happen to also be Honda CRX's
(this is invoking the rule that instances of the subtype are also instances
of the supertype)? The Paint method will fail on those objects which are
Honda CRX's.

Now you will probably say that you should redefine Paint on Honda CRX
as Paint(newColor:blueBlack) and only accept the correct colors.  This
only makes matters worse however because now you have "broken" the code
which was trying to paint the set of cars (some of which are Honda's)
some new color. You can cheat and have the Paint method just do nothing
when the color is wrong, but then you are not building a strongly typed
system (which is another discussion altogether).

No matter how you do it, constraint of any of the signatures of a supertype
in the subtype may "break" the implementation of the supertype or anything
written to work on instances of the supertype.

To me the modifications we term classification can be partitioned into
two parts: one kind of modification which contains constraints like those
above, and are modeled in systems such as the Semantic Data Model
(Hammer and McLeod, ACM Trans on DBS, Sept, 1981), and the other
which can be modeled with inheritance. 

labc-4da@e260-4d.berkeley.edu (Bob Heiney) (05/18/89)

In article <6685@brunix.UUCP> bpe@cs.brown.edu (Page Elmore) writes:
>If you have the types such as:
>
>       Type Car
>          ^    Property: color: allColors (type with instances of all colors)
>          |    Method:   Paint(newColor: allColors)
>          |
>          |
>       Type Honda CRX (inherits from Car)
>               Property color: blueBlack (type with blue and black instances)
>
>
>where Type Car defines a property color which has as it's value type allColors
>and also has a method Paint which takes as its argument an instance of
>allcolors. ...
>The Paint method will fail on those objects which are
>Honda CRX's.
>
>Now you will probably say that you should redefine Paint on Honda CRX
>as Paint(newColor:blueBlack) and only accept the correct colors.  This
>only makes matters worse however because now you have "broken" the code
>which was trying to paint the set of cars (some of which are Honda's)
>some new color. ...

Here we have a conflict that seems to me to be coming from expecting to
impose too much generality on a situation.  In trying to constrain everything
to just one metaphor, we're confusing ourselves.

Certain problems work well with inheritance as specialization of a general
class.  For example, all windows in a window system need to be able to
move to an x,y coordinate, draw themselves, etc.  Here plain old inheritance
works fine.  The windows have compatible features.

But sometimes we want to inherit from a class not because we want to be
compatible with the class, but because we want to extend its services.
For example, BI_LINKABLES which implement two way lists in Eiffel inherit from
LINKABLES.  Now it doesn't make any sense to link a LINKABLE to a BI_LINKABLE
list, so the function that makes links is more specific in BI_LINKABLES than
LINKABLES.  I guess you could say that LINKABLES are really a "subset" of
BI_LINKABLES, but then you still can't link to the left.  The reason
we want to inherit from LINKABLE is not that we want to be treated as
LINKABLEs, but that most of the features of a LINKABLE are things we'll need.
We're inheriting for ease of coding, not for classification.  Our client is the
LINKED_LIST package (only) and it "knows" about the services a BI_LINKABLE
offers.  It needs to know something, whereas a window system could care
less about the features a particular window offers for the most part.

Gettting back to our Hondas, we need to consider how we're using this class.
Since with this example we do seem to want classification, we might provide
another feature in addition to Paint.  A query function,

	Paint_Available(color:allColors) : Boolean 

would be good.  Then a client can ask a Honda if you can paint it a certain
color, and then a precondition of Honda's Paint would be:
Paint_Available(color).

In otherwords, if a feature is a desired property of all descendants
of a class, but not compatible in all descendents of a class, the base
class should provide queries.  If a feature is "like" (note Eiffel
keyword) one in one of its ancestors, but isn't compatible, assume
that the client knows what it's doing, like BI_LINKABLES do.

We're confused because we're using one structure to represent
both simile and metaphor, both "IS_LIKE_A" and "IS_A".  A HondaCRX IS_A car,
but a BI_LINKABLE IS_LIKE_A LINKABLE.

Hope I didn't muddy that waters too much,
-------------------------------------------------------------------------------
| Bob Heiney                         "And in the end, the love you            |
| labc-4da@rosebud.Berkeley.edu       take is equal to the love you make."    |
|                                                     -- The Beatles          |
-------------------------------------------------------------------------------

bpe@brunix (Page Elmore) (05/18/89)

I agree with Bob Heiney's comments -- we are confusing matters by mixing
subsets with subtypes via inheritance. I would say that we need a mechanism
for is-a inheritance which preserves substitutability, and one for subset
which allows classifiction.

Page Elmore
Object-Oriented Database Programming Language Project
Brown University Computer Science Department

jss@hector.UUCP (Jerry Schwarz) (05/19/89)

These comments refer solely to my approach to using inheritance in
C++ as I am not familiar enough with Eiffel or Smalltalk to make
informed comments.

When designing a class it is important to consider what I call the
"protected interface".  This is the interface between the class and
classes derived from it. Part of this specification is what
relationship there will be between the abstractions represented by
the base class and those represented by the derived class.

I know this goes against the "Object Oriented religion", but I
believe that derivation should be done only from base classes that
were designed with derivation in mind and then only in the way that
was intended when the base class was specified.

One possible relation between base and derived class is subsetting.
That is derived classes should represent subsets or the set of
objects represented by the base class. (This seems to be the
intention of the "is-a" advocates.)

Another relation (which I use frequently) is that derived classes
should represent the same things as the base class but with differing
implementations.   This is particularly common when the base classes
is "abstract", i.e. has "dummy" virtual member functions that must be
supplied by derived classes. (In 2.0 there is syntax to allow this
condition to be enforced by the compiler)

Jerry Schwarz
AT&T Bell Labs, Murray Hill

tuck@jason.cs.unc.edu (Russ Tuck) (05/19/89)

Let me say first that I agree with the main points of the article 
quoted below.  However, the particular example chosen can be changed
to avoid the problem and better correspond to "reality".
 
In article <6685@brunix.UUCP> bpe@cs.brown.edu (Page Elmore) writes:
>If you have the types such as:
>
>       Type Car
>          ^    Property: color: allColors (type with instances of all colors)
>          |    Method:   Paint(newColor: allColors)
>          |
>          |
>       Type Honda CRX (inherits from Car)
>               Property color: blueBlack (type with blue and black instances)
>
>where Type Car ...
>also has a method Paint which takes as its argument an instance of
>allcolors. Somewhere in the implementation of paint it sets the color of
>the car to the newly painted color -- an instance of allColors.  Now
>what happens when someone invokes the Paint method with red as the argument
>on members of a set of Cars, some of which happen to also be Honda CRX's
>(this is invoking the rule that instances of the subtype are also instances
>of the supertype)? The Paint method will fail on those objects which are
>Honda CRX's.

If you have a real Honda CRX and pay a body shop to paint it red, what
happens?  Do they say "I'm sorry, we can't do that.  Honda CRXs can only
be black and blue"?  No, they paint it red and you have an unusual red 
Honda CRX that can't be bought directly from Honda.

I think the most natural way to define Honda CRX above is to give it a
constructor that enforces the restriction that all Honda CRXs are *initially*
black or blue.  The color property is inherited unchanged (not restricted).
 
>No matter how you do it, constraint of any of the signatures of a supertype
>in the subtype may "break" the implementation of the supertype or anything
>written to work on instances of the supertype.

Good point.

--
Russ Tuck		               internet: tuck@cs.unc.edu
Computer Science Dept., Sitterson Hall csnet:    tuck@unc
University of North Carolina           uucp:     ...!mcnc!unc!tuck
Chapel Hill, NC 27599-3175, USA        Phone:    (919) 962-1755 or 962-1932

gjditchfield@watmsg.waterloo.edu (Glen Ditchfield) (05/19/89)

In article <6743@brunix.UUCP> bpe@zaphod.UUCP (Page Elmore) writes:
>I agree with Bob Heiney's comments -- we are confusing matters by mixing
>subsets with subtypes via inheritance. I would say that we need a mechanism
>for is-a inheritance which preserves substitutability, and one for subset
>which allows classifiction.

I would put it this way: we should have an inheritance mechanism for code
reuse, and we should have a specification mechanism (perhaps like Russell
signatures) for substitution.  The last means that, if a function wants to
add two parameters, it should specify that the parameters have a '+'
operation.  It should not specify that they must inherit from Number, and
thereby risk excluding strings.
   Alphard did this mostly right, back in the mid 70's.  Alphard let you
say things like
	function f( p1, p2: ?T< plus(T,T) returns T > )
which means that f has two parameters that can be of any type, as long as
that type has a "plus" function.  (Read ?T as "forall T".)
   Alphard also promised data abstraction, inheritance, generic types, and
an elegant approach to iterators that is quite unlike the CLU-style
coroutine approach.  It was a sad day when the Alphard team decided not to
produce a compiler...

    Glen Ditchfield  gjditchfield@violet.uwaterloo.ca  Office: DC 2517
Dept. of Computer Science, U of Waterloo, Waterloo, Ontario, Canada, N2L 3G1
	   waddles like-a Duck & quacks like-a Duck => is-a Duck

fchan@watvlsi.waterloo.edu (Francis Chan) (05/20/89)

It seems we have a consensus that there are two ways to look at
when to sub-classify:

One is the knowledge based approach of sub-classing when there is a case
of IS-A or LIKE-A relations between the super-class and sub-class;  e.g.
the good old "Dog IS-A mammal" example.

The other view is the code-sharing approach which promotes sub-classing
if how a message is handled in the sub-class instance is different from
that of the super-class instance; e.g.  the "LINKABLES" and
"BI-LINKABLES" objects handling of say, an "unlink" message. 

I guess it all boils down to what your application is intended to do. 
If you are doing a knowledge base, then the former sub-classification
scheme seems pretty amenable whereas if you are doing a user-interface,
the latter scheme may be more appropriate.  But in general, it seems
that both type of schemes tend to overlap alot.  And if it doesn't you
can make it so by abstracting to an even higher level e.g.  BI-LINKABLES
and LINKABLES are sub-classes of LINKOBJECTS and instances of
LINKOBJECTS have a body while instances of LINKABLES have a body
(inherited from LINKOBJECTS) as well as links to the right, etc.  Thus,
filling the body would be handled by methods inherited from the
LINKOBJECTS class while linking and unlinking would be handled
specifically by the sub-class methods. Common code pieces (read
common code segments within methods) could be handled as methods
belonging to a super-class.

I have some problems with the Car & Honda CRX examples...

The very fact that class Car was defined to come in a number of colors,
then that's all the colors any sub-class of Car will have.  It is very
constraining, true but that is the whole idea of Object-Oriented
Programming in the first place (or have I got that wrong..).  It is to
provide you with a very clean interface and also the added protection
via encapsulation. 

The fact that there are more colors, and that a paint shop can paint
your Car a different color doesn't matter.  All that means is that the
specification of Car is incorrect.  What you could say is that Car has a
value that is a member of the class CarPaint.  Meanwhile the class
CarPaint will specify what colors are available.  Higher level classes
should not be specific....  let the sub-classes do that.  Be specific
only if you know that all the sub-classes will not affect the value in
any way. 

Most of us are having classification problems because we aren't taught
to program in that mode. If your very first computer language was
object-oriented and you have been using it for awhile (love these
non-specific words), abstraction would probably be the easiest
thing in the world. Global variables ... aieee! Avoid like the
plaque! Modularization is the Law!

Well that's my 2 cents worth... Please note, no flames intended
if that's what they appear to be. All this is my view point of the
sub-classing issue. FLAME-RETARDENT suit is on.

Francis Chan

wlp@calmasd.Prime.COM (Walter Peterson) (05/23/89)

In article <4369@watvlsi.waterloo.edu>, fchan@watvlsi.waterloo.edu (Francis Chan) writes:
> It seems we have a consensus that there are two ways to look at
                     ^^^^^^^^^
> when to sub-classify:


No, I would not say that we have reached a consensus.  ("1. general
agreement, 2. group solidarity in sentiment and belief" -- Webster's
9th Collegiate Dictionary).  In fact, we are far from it; the mere
presentation of opposing points of view does not constitute a consensus.

> 
> One is the knowledge based approach of sub-classing when there is a case
             ^^^^^^^^^^^^^^^^^^^^^^^^
> of IS-A or LIKE-A relations between the super-class and sub-class;  e.g.
> the good old "Dog IS-A mammal" example.
> 
> The other view is the code-sharing approach which promotes sub-classing
                        ^^^^^^^^^^^^^^^^^^^^^


I have some serious reservations about both of these terms.  First,
the idea that the IS-A hierarchy is restricted to knowledge based
applications is not strictly correct.  The IS-A hierarchy with its
HAS-A relations certainly is a significant part of semantic networks
and other forms of knowledge representation, but it has nearly
universal applications.

The very term "code-sharing" worries me.  In object-oriented
programming code is NOT shared, *BEHAVIOR* is shared; the mechanism
for sharing behavior is inheritance.  Let me go back to the case of
the frisbee-catching dog that got me going on this topic.  In that
example, the oringinal poster had a class called "frisb-o-pup"
multiply inheriting from both class "dog" and class "frisbee-catcher".
My objection to that scheme was based on all of the different
behaviors that dogs can perform. That scheme would have separate
classes for "frisbee-catching" dogs, "guide-dog" dogs, "shepherd"
dogs. It would be further complicated by a sheep dog that was also a
good frisbee catcher (on his day off from herding sheep); would that
be an instance of the class "frisb-o-shep-o-pup" ?

Lets further complicate the scheme.  People also catch frisbees, some
better than others.  How would we represent Joe Blow, a programmer,
programming manager, Vietnam veteran, world-class amatuer frisbee
player, etc. ? I hope that everyone can see that it would be ridiculous
to create a class that inherits from "person", "programmer", "manager",
"frisbee-catcher", etc. Joe IS-A person; he *DOES* or *HAS* these
other attributes.  This may sound like a knowledge representation or
knowledge base scheme, but what if the application that we are talking
about is the personel system from Joe's company ?  Not quite what one
thinks of when one hears the term "knowledge base" is it ?

> ....
> 
> I guess it all boils down to what your application is intended to do. 
> If you are doing a knowledge base, then the former sub-classification
> scheme seems pretty amenable whereas if you are doing a user-interface,
> the latter scheme may be more appropriate.


The IS-A hierarchy is totally appropriate for a user interface.  What
kinds of objects are we dealing with in a user interface ?  Windows,
buttons, "volume" controls ( like the bell loudness on a MacIntosh ),
icons, screen coordinates, etc.  A text window IS-A window as is a
graphics window;  the bell loudness IS-A "volume" control as is the
screen brightness control and so on.  

A user interface is no different, conceputually, from any other
application they all have objects that have behaviors and/or
attributes. The fact that some of these objects may be more or less
abstract than others is really immaterial.  In the knowledge
representation realm the object-oriented programmer may be faced with
the problem of representing philosophical or religious beliefs, which
are far from being what most people think of as being "objects" but
they can still be represented in the object-oriented paradigm, just as
well as cars, trucks frisbee-catching dogs and programmers.

My own experience with object-oriented programming is in the area of
CAD/CAM systems and the data management systems to support them.
While there are some elements of knowledge representation in CAD, as
there is in ANY program, it is not a true knowledge representation
application.


>  But in general, it seems
> that both type of schemes tend to overlap alot.  And if it doesn't you
> can make it so by abstracting to an even higher level e.g.  BI-LINKABLES
> and LINKABLES are sub-classes of LINKOBJECTS and instances of
> LINKOBJECTS have a body while instances of LINKABLES have a body
> (inherited from LINKOBJECTS) as well as links to the right, etc.  Thus,
> filling the body would be handled by methods inherited from the
> LINKOBJECTS class while linking and unlinking would be handled
> specifically by the sub-class methods. Common code pieces (read
> common code segments within methods) could be handled as methods
> belonging to a super-class.


Why is there an alarm bell going off in my head and a sign flashing
the word "Kludge" ?  This statement really worries me. It worries me
because this is NOT the only time or place that I have seen it.  In
fact, I have seen it all too often.  Lets all remember that
object-oriented design and programming ALLOWS us to design and write
better software; it does not and can not PREVENT us from writting BAD code.

> 
> I have some problems with the Car & Honda CRX examples...


You are not alone; I have a LOT of problems with it.


> 
> The very fact that class Car was defined to come in a number of colors,
> then that's all the colors any sub-class of Car will have.  It is very
> constraining, true but that is the whole idea of Object-Oriented
> Programming in the first place (or have I got that wrong..).


You have it partly wrong.  Part of the idea of object-oriented
programming is to constrain us to use pre-written classes ( written
by the compiler designer, our project team members, or even by
ourselves ) correctly.  This requires some forethought.
Object-oriented programming should (note: *should*) stop or limit the
all too common practice of throwing something at the computer and
beating on it until it "works"; sort-of.  The Car - Honda CRX and the
frisbee-catching dog example are very poorly thought out, as is shown
by the problems with representing a simple paint job, or a multiply
talented pooch. Thought and an appreciation of the problem being
modeled are what we need in OOPS, not patches.


> 
> The fact that there are more colors, and that a paint shop can paint
> your Car a different color doesn't matter.  All that means is that the
> specification of Car is incorrect.  What you could say is that Car has a
> value that is a member of the class CarPaint.  Meanwhile the class
> CarPaint will specify what colors are available.  Higher level classes
> should not be specific....  let the sub-classes do that.  Be specific
> only if you know that all the sub-classes will not affect the value in
> any way. 
> 


Close, but not quite there yet.  Lets agree that all cars have an
attribute called COLOR (COLOUR for our friends in the U.K.). Now,
what, based upon our common knowledge of cars, can we say about car
colors ?  First of all we can say that ALL cars have color ( at least
I have not seen a totally transparent cars ).  From this we can say
that the color attribute should be defined on the class CAR rather
than on its sub-classes (we may actually define COLOR on some
super-class of CAR, like VEHICLE, but for now lets not).  Now the
question is: should we constrain COLOR or not and if we do, how ?
A quick look arround the streets of Southern California tells me that
cars can come in all colors of the spectrum.  So a VERY broad
constraint might be desirable.  We could have a VERY large enumerated
type called 'color' that would have thousands of color names as its
constants, but that would be rather cumbersome.  We would have to take
into account all of the odd "designer" colors like 'Candy Burgundy
Sparkle'; it is a daunting thought to even consider any resonably broad
enumerated type for car colors.  We can solve the problem by allowing
the COLOR attribte for cars to be a simple character string.

Now we need to consider another factor about car colors; two- three-
and more tone cars are frequently seen. How do we handle this ? The
simplest way is to define COLOR as an aggregate, specifically a set,
since we would only want "blue" to appear once for each blue car.

So how would we deal with the model-T, which came "in any color you
want so long as it is black" ?  THAT is a job for the sub-class
"model-T".  "model-T" can have its own color methods that over-ride
the more general methods on CAR.  These over-ride methods constrain
model-Ts to all be INSTANTIATED as black.  Note the emphasis on
INSTANTIATED; since customizing cars is so common and so easy, methods
should be allowed to change the color, upholstery, wheels, etc. To
facilitate keeping track of these changes we might consider adding a
boolean CUSTOMIZED field to class CAR so that all instances of it and
its sub-classes could tell us if they have been modified.  Things that
are never or very seldom customized, like the frame would not have
methods that would allow us to customize them.  We could add a
CUSTOM-CAR sub-class to CAR that would allow for the really weird
ones.  We can do a lot of things to improve this class hierarchy
definition; there is no one right answer. There are however any number
of WRONG answers. Most of the solutions for the CAR hierarchy that
have been posted here are wrong.




> Most of us are having classification problems because we aren't taught
> to program in that mode. If your very first computer language was
> object-oriented and you have been using it for awhile (love these
> non-specific words), abstraction would probably be the easiest
> thing in the world. Global variables ... aieee! Avoid like the
> plaque! Modularization is the Law!

*mount soapbox*

Most of us were never *taught* anything useful ( 1/2 :-) ).
The most important thing that anyone ( and I might say programmers in
particular ) can be taught is how to THINK.  I have seen too much
reacting, too much copying what others have done and far too little
originality and creative thought on the part of programmers to believe
that our university computer science departments are doing a very good
job in this area.

If your first language was an object-oriented language, you may
actually be at a disadvantage; you don't know just how bad things can
be !  My first language, 17 years ago, was assembly; believe me, I
KNOW how bad it can be.  I can appreciate object-oriented programming
and the potential which it represents.

That potential will only be realized if designers and programmers use
it properly, and that requires thought.  The bad designs that I have
seen here do not so much represent a lack of understanding of the
object-oriented paradigm as they do a lack of thought about the
consequences of the design decisions involved.  My experience with
about 3 years of object-oriented programming tell me that OOPS
requires more thought than other design and programming paradigms.
That increase in thought WILL be worth it.  If you spend the time
'up-front' to think about your design, the detailed design and coding
of the methods will be easy.  Next time you ( that is all of us, not
just the author of the posting being followed up here ) have a design
problem; STOP.  Put the keyboard out of the way. Put the pencil and
paper away. THINK.  Then put it down on paper as an object model
( you can use the keyboard if and only if you have the necessary CASE
software to draw your model on the screen ).  See if you have created
any problems for youself like the Honda CRX or the "frisb-o-shep-o-pup".
If you have, DO NOT try to "patch" it up or find work-arrounds;
RE-DESIGN you object model. Start that redesign by going back to
step one: THINK.

*dismount soapbox*



-- 
Walt Peterson.  Prime - San Diego R&D (Object and Data Management Group)
"The opinions expressed here are my own."

kasper@iesd.dk (Kasper Osterbye) (05/24/89)

Then here is my N cents of ideas for this discussion.

First I believe that inherritance are used for two things. It is
used for classification in descriptions of real world entities, eg.
the IS-A relation. This is an important use especially when seen
in connections to systems build around the JSD architecture, which
is also advocated by Meyer (though not so explicitly).
    JSD is Jackson System Development method, described in Michael
    Jackson, System Development, Prentice-Hall, 1983. Highly recommended!

Second inheritance is used for code-sharing (or behaviour-sharing
if that is a less upsetting word). This can be seen in Smalltalk
where Semaphore is a subclass of linked list.

My observation is that both of these views are important, but they
unfortunately get in the way of each other. I see some solutions
to this.

Solution number 1.

This example is along the lines of the frisbee-catching-brown-sheepdog.
In flavors they have a notion of mixin's. (I am not very familiar
with Flavours, and got the idea from elsewhere, but the word mixin
is good for this example). If we take a class car, we can write a
number of classes that describe various features that can be added
to cars. PowerSteering, Sunroof, CarStereo, automatic shift etc.

When I need a car, I make a subclass of car, MyCar. But in making
that subclass I can use anynumber of mixins I care for (and can pay
for). If I make a Car1 with stereo and a Car2 with Sunroof. If I
now want a car with both stereo and sunroof, I do not make a subclass
of Car1 and Car2, but rather a new subclass of Car, Car3 with the
stereo and sunroof mixins.

An other classical example of multiple inherritance is the window
example, where we have window, titlebars, scrollable windows and
boardered windows. Again, the titlebar, scrolling, and boarder can
be made features/mixins to be used in for concrete windows.

Now what are these secondary classes in the inherritance. In my examples
they do not represent the IS-A relation, but rather the HAS-PART
relation. They are used as aggregation rather than specialization.
Also a very good example is that it makes sence to inherrit from
the same mixin twice (or more), I might want to add two sunroofs
in my streched limosine. Or a person could have two programming jobs,
thus being a programmer twice.

Also these special classes like sunroof are not intended as stand
alone classes, and they can normally not be used as mixins for other
classes. (A horse or a bike with sunroof?). That is they are intended
to serve as PARTS.


Solution number 2.

One could considder a language where we had a specification of the
class in some higher level language. These specifications could be
organized in a hierarchy also, but not necessaly following the class
hierarchy. The hierarchy of the specifications could then be made
to follow the IS-A relation, as there is no need for code-sharing
in specifications. And the classes could be organiced in a code-sharing
hierarchy. I have not thought about this solution as much as the
other one.


For anyone interested, I am working on a paper of the first solution,
that I can send/mail (its in latex).

Regards,
    Kasper.


-- 
Kasper Osterbye                     Internet: iesd!kasper@uunet.uu.net
Institute for electronic systems    UUCP: ...!mcvax!iesd!kasper
Strandvejen 19, 9000 Aalborg
DENMARK. (W) +45 98 13 87 88-285  (H) +45 98 37 30 65