[OT?] Multiple Inheritance (was Re: hash arrays and other mysteries)
[OT?] Multiple Inheritance (was Re: hash arrays and other mysteries)
- Subject: [OT?] Multiple Inheritance (was Re: hash arrays and other mysteries)
- From: Chris Page <email@hidden>
- Date: Tue, 23 Oct 2001 05:29:22 -0700
[Warning: Long, possibly off-topic, lecture in OOP coming up...don't let me
type late at night when there's nobody to interrupt me...:-]
nigh on 2001.10.22 2:10 PM, Paul Skinner at email@hidden wrote:
>
> AppleScript doesn't have multiple inheritence, true. But neither does
>
> Smalltalk or Java. From an object-oriented design perspective, multiple
>
> inheritence is questionable.
>
>
>
Hmmm. I'm trying to think of why it's questionable. Complexity?
>
Anyway, AppleScript does have it. No, a script can't have two parents,
>
but it can have a family tree.
>
If the script which is a script's parent has a parent then the child
>
script ( or grandchild script ) inherits from both parent scripts.
What you're describing is still called single inheritance; there's only one
line of inheritance through all the parents, and the direct parent can
modify any of its parents or their parents, etc. In multiple inheritance, a
child can have more than one direct parent, and those parents do not usually
modify each other's behavior or attributes.
To answer your question: In fact, multiple inheritance (MI) can often reduce
complexity found in a single inheritance (SI) class hierarchy.
For example, MI can be used to simplify and flatten an object hierarchy. If
you have the following classes: <bird>, <dove>, <penguin>, you might arrange
them in this hierarchy:
<bird>
/ \
<dove> <penguin>
But what if you want to have a "fly" handler? Doves fly, but penguins don't.
When you only have SI, you might arrange it like this:
<bird>.fly
/ \
<dove> <penguin>
(Where ".fly" indicates the "fly" handler belongs to the <bird> class)
But what would "fly" do for penguins? Would it report an error? How could
you tell which birds can fly? Add a separate "can_fly" handler? One solution
is to introduce an intermediate class for flying birds:
<bird>
/ \
<flying-bird>.fly <penguin>
/
<dove>
Now, penguins can swim, but (let's assume) doves don't. And furthermore,
ostriches don't fly or swim, whereas (in my hypothetical taxonomy) ducks
fly, run, and swim. As you can see, we could keep inserting classes such as
<running-bird> and <swimming-bird>, but then we'd have to add
<running-swimming-bird> and who knows how many more "combination" classes to
reflect the full array of bird possibilities. The hierarchy would get
complicated and more difficult to maintain.
And it only gets worse when you decide to model a greater section of the
animal kingdom, where there are other animals that can fly and swim and run,
and so on. Furthermore, it doesn't add anything to the program to have a
<running-swimming-bird>, since running and swimming are (generally) separate
activities.
Now we turn to MI. Instead of <flying-bird> and <swimming-bird> directly
inheriting from <bird>, they can be entirely separate classes, and various
bird subclasses can inherit properties from whichever and as many of these
classes as are applicable. (These are often called "mix-in" classes, because
you have one main line of inheritance, e.g., <animal> - <bird> - <dove>, and
then you "mix-in" additional attributes.) So our class hierarchy would tend
to look more like this:
<flyer>.fly <bird> <swimmer>.swim
\ / \ /
<dove> <penguin>
And as you can see, we could add <runner> and <burrower> and so on, and
still only have two levels in the hierarchy, and each class of bird would
only inherit from those parents that are meaningful to them.
As you might guess, it becomes difficult to draw a simple 2D graph of a
large collection of classes that use MI, but on the other hand it's easier
to draw the inheritance hierarchy of a particular class or subset of classes
than when you have a deep SI tree, and this fact mirrors the conceptual
complexity associated with each approach.
Most of the time you try to focus on a single class or a small subset of the
hierarchy when thinking about a program (that's the point of OOP). With a
deep SI hierarchy you have to be concerned not only with the effect each
parent has on the class of interest, but you also have to consider the
affect that every parent class has on its parent and its grandparent, and so
on. With a flatter MI hierarchy you have a shorter parent chain and you only
have to think about the classes that the class you're interested in really
uses.
'Course, you can go overboard in the other direction with MI and have a
fragmented collection of classes with no obvious relationships. You have to
properly use MI and SI as tools to strike the right balance.
Hope I haven't bored anyone.
--
Chris Page
Mac OS Lead, Palm Desktop
Palm, Inc.
This is software development we9re talking about here.
3Picky2 is our mantra.