[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