[comp.lang.misc] object oriented design decision

dan-hankins@cup.portal.com (Daniel B Hankins) (10/29/88)

An addendum to my previous posting:  In the case where one wishes to inherit
everything from a parent save a few individual message handlers or local
variables, one might want something like:

class X;
  superclasses A, B, C;
  from A discard Y;
 .
  . 
  .

This would allow even more flexibility in inheritance.  Another alternative
is to handle name importing the way Modula-2 does - if an individual name
is wanted, one specifies

from X inherit Y

but if complete inheritance is wanted,

inherit X

is used, and references to names in X must be prefixed with their class name,
as in:

tell X.K move-arm


Any ideas or suggestions?

Dan Hankins

dan-hankins@cup.portal.com (Daniel B Hankins) (11/13/88)

Thanks for all the email responses to my query.  To summarize:

Multiple inheritance is an indication that something is wrong with the class
hierarchy.  Restructure that and single inheritance should do fine.  This
also does away with things like the specific inheritance mechanism and
method/variable drop clauses.

Lexical scoping inhibits reusability.  Solution: allow multiple classes with
the same name, and distinguish them on the basis of what their superclass
chain is.  Since this language has no declaration of variable class (all
type checking is done by something like lint, and at runtime), this won't
create problems with the user having to type in unmanageably long names
in type declaration statements.

Dan Hankins

steve@ragman (Steve Stevenson) (11/14/88)

From article <11256@cup.portal.com>, by dan-hankins@cup.portal.com (Daniel B Hankins):
> Thanks for all the email responses to my query.  To summarize:
> 
> Multiple inheritance is an indication that something is wrong with the class
> hierarchy.
> 
> Lexical scoping inhibits reusability.

I think these are the same problem.  The insistance on a hierarchy
may put you in a bind both performance wise and logically.  Recall
the problems with type theory in general.  Another problem is that
a hierarchy of true ABSTRACT data types ( in the sense that a queue
apart from any implementation ) is not tantamount to a package or
module.

ech@poseidon.ATT.COM (Edward C Horvath) (11/15/88)

From article <11256@cup.portal.com>, by dan-hankins@cup.portal.com (Daniel B Hankins):
> Thanks for all the email responses to my query.  To summarize:

> Multiple inheritance is an indication that something is wrong with the class
> hierarchy.  Restructure that and single inheritance should do fine...

I used to think so, too.  Then I read Meyer's book: multiple inheritance
is a concept with immense power, not a "hack."

I am less convinced of the need for REPEATED inheritance, i.e.  inheriting
from two or more classes with a common ancestor.  Even here, however,
notions like nodes which are simultaneously on two types of linked
lists are well-served by repeated-inheritance-with-renaming.

=Ned Horvath=

sommar@enea.se (Erland Sommarskog) (11/18/88)

Daniel B Hankins (dan-hankins@cup.portal.com) writes:
>Thanks for all the email responses to my query.  To summarize:
>
>Multiple inheritance is an indication that something is wrong with the class
>hierarchy.  Restructure that and single inheritance should do fine.  
 
Could anyone elaborate this? I fail to see what is bad with multiple 
inheritance. If I want to store an object in a tree and a 
linked list simultaneously, what is wrong with my class structure?

-- 
Erland Sommarskog
ENEA Data, Stockholm
sommar@enea.se
A radio station is a four-letter word.

dan-hankins@cup.portal.com (Daniel B Hankins) (11/20/88)

In article <795@euraiv1.UUCP> reino@euraiv1.UUCP (Reino de Boer) writes:
>How about having two separate classes for a linked list:
>Class List
>Class EmptyList
>and trying to build a stack as subclass of List and EmptyList.  Isn't
>multiple inheritance nicer than trying to make class List act like two
>separate concepts ?

I suggest trying to pick a better example.  It seems to me that if you are
going to have two separate classes for a linked list, you might as well
have two separate classes for a stack.  In this case, those classes would
be Stack and EmptyStack, which would be subclasses of List and EmptyList,
respectively.


In article <578@poseidon.ATT.COM> ech@poseidon.ATT.COM (Edward C Horvath)
writes:
>> Multiple inheritance is an indication that something is wrong with the class
>> hierarchy.  Restructure that and single inheritance should do fine...
>
>I used to think so, too.  Then I read Meyer's book: multiple inheritance
>is a concept with immense power, not a "hack."
>
>I am less convinced of the need for REPEATED inheritance, i.e.  inheriting
>from two or more classes with a common ancestor.  Even here, however,
>notions like nodes which are simultaneously on two types of linked
>lists are well-served by repeated-inheritance-with-renaming.

In article <4086@enea.se> sommar@enea.se (Erland Sommarskog) writes:
>>Multiple inheritance is an indication that something is wrong with the class
>>hierarchy.  Restructure that and single inheritance should do fine.  
> 
>Could anyone elaborate this? I fail to see what is bad with multiple 
>inheritance. If I want to store an object in a tree and a 
>linked list simultaneously, what is wrong with my class structure?

These two sound like the same example.  In either case, is is much better
programming practice to have a class Node which is not tied to any
structure.  Objects which are nodes of class TreeNode or ListNode or
whatever should have objects of class Node as an acquaintance (or variable,
in Smalltalk terminology).


In article <678@quintus.UUCP> pds@quintus.uucp (Peter Schachte) writes:
>A better example is toy truck.  A toy truck IS a toy and it IS a truck,
>so it might make sense to have it inherit from both.  It could inherit
>number-of-wheels from truck, and qualitative-size from toy.  But
>dealing with the conflicts, it seems to me, is nontrivial at best, and
>sometimes a quagmire of hacks.
>
>Does someone have a GOOD theory of multiple inheritance that deals with
>conflicts in more than an ad hoc way?

This is the tricky one.  This is the one that makes me think that perhaps
a tree, or even a digraph, is not the proper way to think about classifying
objects.

What is the proper way?  I'll let you know when and if I figure it out.


Dan Hankins

halvers@phecda.steinmetz (Pete Halverson) (11/21/88)

From my experience, multiple inheritence seems to be most useful when
you're trying to represent characteristics that are somehow orthogonal,
i.e. land vehicles vs. sea vehicles, motorized vs. non-motorized, military
vs. commercial.  Single-inheritance-only schemes require you to define a
separate class for each combination (i.e. Motorized-Military-LandVehicle,
NonMotorized-Commercial-SeaVehicle).   If you have many dimensions and many
subclasses, the resulting cross-product is going to get real nasty, real
fast. 

Not to say these kinds of systems aren't complex (I'm currently in the
midst of trying to decipher the Symbolics window class structure) but
multiple inheritance can at least directly represent these orthogonalities.

frode@m2cs.naggum.se (Frode Odegard) (11/21/88)

In article <4086@enea.se>, sommar@enea.se (Erland Sommarskog) writes:
>  
> I fail to see what is bad with multiple inheritance. If I want to
> store an object in a tree and a linked list simultaneously, what is
> wrong with my class structure?
> 
> -- 
> Erland Sommarskog
> ENEA Data, Stockholm
> sommar@enea.se
> A radio station is a four-letter word.


Some people are worried about the dependency problems and structure
implications of allowing multiple inheritance. To my knowledge,
Eiffel is the only commercial system which supports multiple inheritance
[except LISP-based systems?] and it will be interesting to see if
the reactions will continue to be so positive as they've claimed them
to be so far..

The company I work for is developing an advanced Modula-2 environment
where a lot of the effort in supporting large-scale projects (i.e.
multi-site, 200,000+ loc etc..) has gone into designing formal notations
for defining architecture and dependency demands which go beyond the
scope of the Modula-2 itself. I guess the conclusion we've reached
is that it is easier to solve structural problems (like dependency
management) when the language is simple, rather than have a HUGE
language for which it is difficult to build an equally powerful
environment [look at Ada: only Rational has been able
to come up with a decent environment, and that's 2 million lines
of Ada code, they claim].

The OOP fever has many similarities to the RISC fever. People seem
to think that as long as something is O-O it is good. This is simply
not true. Using notations which support refinement and extension of
previously written software components is going to help you in terms
of productivity, but you're still going to get maintenance problems
and in an environment like Smalltalk, you just don't go in and
fiddle too much with class dependencies :-)

National Semiconductor (which hasn't announced any RISC processor
yet) has stated that "RISC is a technology - not a product". Perhaps
it is time to be more rational about OOP, too. OOP is a new approach
to problem-solving, it's exciting, but it's not the only way of
getting good results. Sometimes it can be worth the trouble to mix
O-O approaches with others. Our Modula-2 environment, for example,
is based around a distributed object-oriented database, but we
didn't create an O-O database *programming* language. There's a new
notation for declaring database classes, but the methods are implemented
in standard Modula-2.

Sigh..I know...I know...not of all this deals with multiple inheritance,
but I got kinda carried away.

See U all on the bit-stream!

				- Frode

akwright@watdragon.waterloo.edu (Andrew K. Wright) (11/21/88)

In article <11522@cup.portal.com> dan-hankins@cup.portal.com (Daniel B Hankins) writes:
>This is the tricky one.  This is the one that makes me think that perhaps
>a tree, or even a digraph, is not the proper way to think about classifying
>objects.
>
>What is the proper way?  I'll let you know when and if I figure it out.

The real world is full of all kinds of arbitrary relationships.
If you want to directly model the real world, you will have to
allow arbitrary relations in your language, ie. an arbitrary graph.

The object oriented approach seems to be "the real world is too complicated;
lets fix it (force it into a tree) and then model it".
This works fine when the problem you are trying to model fits
your inheritance tree naturally, but when the fit is unnatural, you
have given the programmer some more work.

An approach which seems to offer more promise of modelling the real world
directly is parametric polymorphism.  Algorithms rather than objects
specify what other algorithms they require to operate.  Universal
and existential quantifiers can be used in the type specification of
algorithms to make algorithms more reusable.  For example, here
is the type specification for "sort", which can sort arrays of any type:

	sort: [ forall t: type,
			forall i: int,
			forall j: int,
			exists >: [t,t] bool,
			       a: [i..j] array t
		  ] proc void;

This says "sort" operates on arrays of any type and any number of elements,
so long as the function ">" is defined between the elements.

This is a simplified example; a general sort would not require the
data structure to be an array.  Sorting linked lists may be equally
desirable, and requires sort to be further generalized to require
that swap (or := and a temporary constructor) exist.
--------
Andrew K. Wright      akwright@watmath.waterloo.edu
CS Dept., University of Waterloo, Ont., Canada.

sommar@enea.se (Erland Sommarskog) (11/22/88)

Daniel B Hankins (dan-hankins@cup.portal.com) writes:
>I said:
>>If I want to store an object in a tree and a 
>>linked list simultaneously, what is wrong with my class structure?
>
>These two sound like the same example.  In either case, is is much better
>programming practice to have a class Node which is not tied to any
>structure.  Objects which are nodes of class TreeNode or ListNode or
>whatever should have objects of class Node as an acquaintance (or variable,
>in Smalltalk terminology).

So If have a link and a tree class just lying around I should just 
ditch them in favour of a more general node class which I haven't? 
So much for reuseable software!
  And I fail to see how I make it with my objects as nodes simply. 
I want to apply typical list operations as delete/insert them into
the list, go to the next element and so. And I want to visit all
of them in prefix order, insert them sorted into the right place in
the tree, and so on.
-- 
Erland Sommarskog
ENEA Data, Stockholm
sommar@enea.se
"Frequently, unexpected errors are entirely unpredictable" - Digital Equipment

nobody@tekecs.TEK.COM (-for inetd server command) (11/23/88)

In article <12636@steinmetz.ge.com> halverson@crd.ge.com (Pete Halverson) writes:
>From my experience, multiple inheritence seems to be most useful when
>you're trying to represent characteristics that are somehow orthogonal,
>i.e. land vehicles vs. sea vehicles, motorized vs. non-motorized, military
>vs. commercial.  Single-inheritance-only schemes require you to define a
>separate class for each combination (i.e. Motorized-Military-LandVehicle,
>NonMotorized-Commercial-SeaVehicle).   If you have many dimensions and many
>subclasses, the resulting cross-product is going to get real nasty, real
>fast. 
>
>Not to say these kinds of systems aren't complex (I'm currently in the
>midst of trying to decipher the Symbolics window class structure) but
>multiple inheritance can at least directly represent these orthogonalities.

I'm not really "for" or "against" multiple inheritance,
but I haven't seen anything that shows that multiple inheritance
really adds anything.

Couldn't you have one vehicle class with 3 instance variables?
One instance variable for each of the "dimensions"
(e.g.  surface: land vs. sea, propulsion: motorized vs. non-motorized, ...).
The vehicle class could forward messages to the appropriate instance variable.
Some OO languages allow methods to be expanded in line,
and can often avoid the extra method lookup,
so that the forwarding wouldn't have to incur a run time penalty.

Adding, for example, more surfaces for vehicles
(e.g. add to land and sea the surfaces air, space, ...)
wouldn't have to require changes to the vehicle class.
This doesn't seem to have the cross-product effect you were talking about.

Or maybe I just didn't understand the problem,
Paul Scherf, Tektronix, Box 1000, MS 61-028, Wilsonville, OR, USA
paulsc@orca.GWD.Tek.COM			tektronix!orca!paulsc

barmar@think.COM (Barry Margolin) (11/24/88)

In article <10660@tekecs.TEK.COM> paulsc@radio_flyer.UUCP (Paul Scherf) writes:
>but I haven't seen anything that shows that multiple inheritance
>really adds anything.
>
>Couldn't you have one vehicle class with 3 instance variables?
>One instance variable for each of the "dimensions"
>(e.g.  surface: land vs. sea, propulsion: motorized vs. non-motorized, ...).
>The vehicle class could forward messages to the appropriate instance variable.
>Some OO languages allow methods to be expanded in line,
>and can often avoid the extra method lookup,
>so that the forwarding wouldn't have to incur a run time penalty.

This has a few problems.  One is that each time you think of a new
dimension you must modify the vehicle class in order to add a new
instance variable to embody that dimension.

A more serious problem is that these sub-instances are running with
the wrong notion of "self".  If they perform an operation on self they
will not be operating on the whole vehicle, just their own aspect.
"Self" is a very important concept in OO programming, as it allows a
method in a component class to perform an operation whose results
depend on the actual class of the object.

With this workaround for the lack of multiple inheritance, each
sub-instance must either have an instance variable holding its parent,
or every operation must pass the parent as an argument.  But you would
also need the grandparent, the great-grandparent, etc.  Multiple
inheritance automates and generalizes this in an elegant manner.

By the way, your suggestion can actually be used as an argument
against inheritance in general, since the same mechanism could be used
to pass on operations from a class to a single superclass.  I believe
there are some OO systems that work this way.  I don't know how they
deal with the "self" issue.

Barry Margolin
Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

pds@quintus.uucp (Peter Schachte) (11/24/88)

In article <9861@watdragon.waterloo.edu> akwright@watdragon.waterloo.edu (Andrew K. Wright) writes:
...
>This says "sort" operates on arrays of any type and any number of elements,
>so long as the function ">" is defined between the elements.
>
>This is a simplified example; a general sort would not require the
>data structure to be an array.  Sorting linked lists may be equally
>desirable, and requires sort to be further generalized to require
>that swap (or := and a temporary constructor) exist.

But that's not a good idea, efficiency-wise.  You might want to use
Quicksort to sort arrays, but you sure wouldn't want to use it for
lists.  You'd probably use a merge sort.

Take it even a step farther.  If the type of element you're sorting is
small, and comparison is cheap (e.g., sorting integers) you'd want to
use quicksort.  If the number if distinct keys is small, you might use
a radix sort.  If the data to be sorted will not fit in memory, maybe
you'd use a heapsort to get sorted pieces followed by merge passes.

If you're talking about real-world constraints that make
single-inheritance systems painful, there are also real world
constraints that make a polymorphic system painful, too.  Nothing's
perfect.
-Peter Schachte				"Clean water?  I'm for clean water."
pds@quintus.uucp				-George Bush
..!sun!quintus!pds

pds@quintus.uucp (Peter Schachte) (11/24/88)

In article <12636@steinmetz.ge.com> halverson@crd.ge.com (Pete Halverson) writes:
>From my experience, multiple inheritence seems to be most useful when
>you're trying to represent characteristics that are somehow orthogonal,
>i.e. land vehicles vs. sea vehicles, motorized vs. non-motorized, military
>vs. commercial.  Single-inheritance-only schemes require you to define a
>separate class for each combination (i.e. Motorized-Military-LandVehicle,
>NonMotorized-Commercial-SeaVehicle).   If you have many dimensions and many
>subclasses, the resulting cross-product is going to get real nasty, real
>fast.

In article <10660@tekecs.TEK.COM> paulsc@radio_flyer.UUCP (Paul Scherf) responds:
>Couldn't you have one vehicle class with 3 instance variables?
>One instance variable for each of the "dimensions"
>(e.g.  surface: land vs. sea, propulsion: motorized vs. non-motorized, ...).
>The vehicle class could forward messages to the appropriate instance variable.
>Some OO languages allow methods to be expanded in line,
>and can often avoid the extra method lookup,
>so that the forwarding wouldn't have to incur a run time penalty.

I see two problems with this approach.  First, it's a pain to define
lots of methods for vehicle that just forward the message to the
appropriate instance variable.  More seriously, though, the object
receiving the message is no longer the one you're really talking about,
so self messages go to the wrong place.  For example, suppose vehicle
has a position message that returns the vehicle's position, and both
motorized and non-motorized define a halt method.  Further suppose that
in one or both cases, halt needs to know the vehicle's position.  The
obvious way to do this is to send a position message to self.  But this
won't work, because self is motorized or non-motorized, rather than the
vehicle.

Well, you can patch around this by having a back-pointer from motorize
and non-motorized to the vehicle, and having methods for all of
vehicle's messages that forward to the vehicle.  That of course means
that you have to have a separate motorized object for every motorized
vehicle you create.  It starts getting ugly.

I think a similar approach could work quite well, though, if it were
built into the OO system.  It would have to understand attributes, like
propulsion in the above example.  An attribute would be like a class,
except that they can't be instantiated, and a class can specify that
certain attributes must be specified when it is instantiated.  So vehicle
would be a class that requires propulsion, which would be an attribute
(sort of like a mixin, for flavors people).  An attribute specification
would include a set of methods that its instances (this is probably a
bad choice of word -- in this case I mean motorized and non-motorized)
must supply.  When an instance of vehicle it gets all the methods from the
vehicle class, plus the methods from the chosen attribute.  But it's
still a single object.

I hope I'm being at least faintly clear.
-Peter Schachte
pds@quintus.uucp
..!sun!quintus!pds

dan-hankins@cup.portal.com (Daniel B Hankins) (12/04/88)

In article <737@quintus.UUCP> pds@quintus.uucp (Peter Schachte) writes:

>I think a similar approach could work quite well, though, if it were
>built into the OO system.  It would have to understand attributes, like
>propulsion in the above example.  An attribute would be like a class,
>except that they can't be instantiated, and a class can specify that
>certain attributes must be specified when it is instantiated.  So vehicle
>would be a class that requires propulsion, which would be an attribute
>(sort of like a mixin, for flavors people).  An attribute specification
>would include a set of methods that its instances (this is probably a
>bad choice of word -- in this case I mean motorized and non-motorized)
>must supply.  When an instance of vehicle it gets all the methods from the
>vehicle class, plus the methods from the chosen attribute.  But it's
>still a single object.
>
>I hope I'm being at least faintly clear.

     I had to think about this one for a while.  For a while I thought it
was the same as multiple inheritance.  But I can see that it has potential
for a more natural expression of an object description.  Objects are
like nouns, messages/methods are like verbs, and attributes are like
adjectives and adverbs.

     However, your description is a little confusing.  Could you possibly
append an example of a class definition using attributes, and an example of
an attribute definition?

     Also, how do you get attributes to work together?  How do you get them
to agree on variable names which are meant to be shared, such as for
example vehicle position?


Dan Hankins