[PEAK] PEAK Components: beginner questions
Phillip J. Eby
pje at telecommunity.com
Wed Sep 22 00:34:50 EDT 2004
At 10:56 PM 9/21/04 -0400, Duncan McGreggor wrote:
>>>* What's the best way for an interface to inherit from another
>>>interface? (I know this has been discussed... I just can't find it)
>>
>>That depends on what you mean by "inherit". I'm sure I don't know what
>>you mean, since you have lots of interface inheritance in your example.
>
>Specifically:
>
>class IBody(Interface):
>...
>
>class IPhysiology(IBody):
>...
>
>Given that the interfaces make sense and it is genuinely appropriate for
>IPhysiology to inherit from IBody,
Is it really?
>is this how it should be done? Or is there a PEAK way of doing it?
>
>Usage clarification: IPhysiology would only be used in software agents
>simulating living entities; with them, there would be no implementation of
>IBody. However, a manufacturing robot (e.g., one you would find in an
>assembly line) simulation would implement IBody (and obviously not
>IPhysiology).
Then clearly there isn't an inheritance relationship. Inheritance should
follow the Liskov Substitution principle: the subclass may be used wherever
the superclass is called for.
Specifically, your "software agents with no IBody" could not be used where
an IBody was called for, could they? That means that IPhysiology *isn't* a
body.
Inheritance is an "is-a" relationship. Is a physiology a body? Heck if I
know, I find your example interfaces and methods sufficiently weird that I
have no intuition about whether that makes any sense. But going off of
what you say here, I would say that this is *not* an inheritance
relationship. And, if I go off the (normal English) meaning of the words
"body" and "physiology", I might think that a body was a physiology, or
that a body has a physiology, but I absolutely would not think that a
physiology is a body! (And therefore, wouldn't expect to see IPhyisology
derive from IBody.)
A general word also about interface design: interfaces are about behavior,
and you should question any interface whose name is a noun that doesn't
imply behavior. I don't know what a physiology or a body is supposed to
*do* from just those names. Contrast with interface names in PEAK:
adjectives such as 'IAttachable', 'IConfigurable', and even the nouns tend
towards action descriptions: 'IResolver', 'IObjectFactory'.
Of course, maybe half of PEAK's interfaces don't *really* follow this
advice as well as they might, and now that I'm actually looking at them
through the lens of this advice I just make up, I think some of 'em ought
to be renamed. :)
But I digress. The point is, an interface usually is -- or should be --
about a single, clear responsibility. Generally speaking, you don't want
to lump multiple responsibilities into an interface, because you might want
to perform them using different objects at some point, and at that point
you would already have a bunch of code expecting those responsibilities in
one object.
Inheritance usually comes into play when some clients of the interface need
additional capabilities, but not all suppliers of the interface will be
able to provide those additional capabilities. Or, sometimes there's a
component that for convenience reasons will aggregate a variety of
features, and you use inheritance to assemble an interface from the various
sub-interfaces.
>>>* Right now, a physiology instance p has to use p.body to get to the
>>>Body methods; is there are better/more direct way to do this? Seems a
>>>little awkward... (since I'm used to object inheritance)
>>
>>You can use inheritance, if you like. But if you want to delegate, use:
>>
>> getFuelLevel = getDamageLevel = binding.Delegate('body')
>>
>>as I mentioned earlier. This is roughly equivalent to:
>>
>> getFuelLevel = binding.Obtain('body/getFuelLevel')
>> getDamageLevel = binding.Obtain('body/getDamageLevel')
>>
>>only more succinct.
>
>What are some of the factors one should consider when deciding on to use
>inheritance in a case like this, or delegation? I.e., when might/should
>one choose one over the other?
Delegation lets you (or a consumer of your code) change your mind about
things, whereas inheritance does not. Therefore, inheritance should only
be used for "is-a" relationships, not "has-a" relationships.
A key example of why delegation is often superior: if we had our
MicrowaveOven class inherit from a PowerSupply, a RadiativeElement, and so
on, then creating another kind of MicrowaveOven would be complex, to say
the least.
However, with delegation, we can actually assemble new kinds of microwave
ovens *at runtime*, either by setting instance attributes, or using a
ZConfig schema to define a file format for specifying how a particular oven
will be assembled. Or, if our application is only going to simulate one
kind of microwave oven at a time, we can define our abstract oven using
e.g. 'binding.Make(IPowerSupply, offerAs=[IPowerSupply])', and use an .ini
file with something like this in it:
[Component Factories]
microwave.IPowerSupply = "us_power.SuperSupply"
microwave.IControlPanel = "outsourcer.Panel27"
# etc..
PEAK will then import and instantiate the correct classes when the
attributes of the oven are accessed.
None of these things are as practical if you use inheritance.
>In fact, we won't have an implementation called "Emotion" ... probably
>something more like emotion.StandardOCCModel,
>emotion.SilvermanMarkovOCCModel, etc., with one of them being used in a
>software agent at any given time... and I guess the possibility exists for
>the combination of multiple models. That might have to be done at the
>class level, as opposed to achieving it through use of components... need
>to give that more thought.
Or, by use of a "composite" - an object that implements IEmotion, given a
collection of other IEmotions. PEAK uses composites quite a bit; for
example, a tuple of IRecipe-implementing objects is considered a recipe for
a tuple of the objects defined by the individual recipes.
>In fact, I have re-read this email multiple times throughout the day, and
>each time I glean some additional insight into not only PEAK, but design
>decisions as well.
That's because PEAK was created in part to articulate some design
philosophies and techniques that Ty Sarna and I evolved over a fairly long
period of time. It's intended to make it easy to do things in sensible
ways. :)
In fact, as you and others have noticed, the *hardest* thing to deal with
in learning PEAK is to stop making it so much more complicated than it
is. It *is* more complicated than just throwing a script together, for
many things. But, if you are going to write something that needs to scale,
evolve, and be maintained for a period of time, the overhead is definitely
worth it, as it's far *less* complex than alternatives like re-inventing
all the wheels that come bundled with it.
More information about the PEAK
mailing list