Variable inheritance

Alex Martelli aleaxit at yahoo.com
Tue May 22 16:18:46 EDT 2001


"Roman Suzi" <rnd at onego.ru> writes:
    ...
> This gives better granularity than MI could provide.

Feature-granularity is a completely orthogonal issue
from one of implementation -- it's part of the specs!

The user in my example is picking a bridge-bidding
system out of a set of agreements, and some subsets
just MUST go together or are incompatible -- this is
my decision as an application-field expert analyst,
and I won't LET it be dictated by implementation level
concerns!  Do YOU let the coding tail wag the dog
of specs?!

> Just pick your fetures directly, why do you need
> inheritance?

As an implementation-level decision, I don't want to
have to code selection logic in my application-level
objects, given that the language gives me a much
better mechanism in its polymorphism implementation
via MI.  Isn't that obvious?  Why re-do something the
language does perfectly well?!

The user is going to write scripts in some language or
other that use the 'objects' he has created, and other
framework-level objects I supply.  As it happens, as
the language in question I have chosen Python, as I
happen to like it a LOT (don't you?), so the objects
must be Python-callable (some stereotypical simple
scripts may be written via code generator, but, even
then, inheritance is the RIGHT code-reuse technique:
the user does NOT edit the code-generator-written
code, he or she INHERITS from classes built by the
code-generator if any tweaking is needed... as a
matter of course, I should say!).

So why should each object the user sees implement
a __getattr__ and duplicate the same search process
that Python ALREADY gives me for free, provided
only that I use inheritance?!  *WHAT IS SUPPOSED
TO BE THE ADVANTAGE* of recoding from scratch, in
Python, mechanisms that are already perfectly well
provided by the language infrastructure?!


> >I don't see how aggregation and delegation would be easier
> >to implement and maintain than this simple framework.
> 
> It depends. Python has great functional capabilities
> to make container-writing (with proper dispatching
> of messages) very easy.

Sure.  And the simplest of such functional capability
is called INHERITANCE -- the premier code reuse
technique.

> I can't agree Python's MI is a way to do HAS-A
> relations. It seems to me like using only

"Has-A"?  Who cares about that?!  All I ever want from
inheritance (and overriding, etc) is BEHAVES-LIKE.

An elementary bridge-hand-evaluation class, for
example, will have some kinds of behaviors such
as:

class SimpleEvaluate:
    def high_card_points(self):
        return reduce(operator.add,
            map(self.honor_value, self.card_ranks))
    def shape_points(self):
        return reduce(operator.add,
            map(self.lengh_value, self.suit_lengths))
    def length_value(self, suitlen):
        return max(0, 3-suitlen)
    def honor_value(self, cardval):
        return max(0, cardval-10) #a=14, k=13, ...
    def dh_points(self):
        return self.high_card_points()+self.shape_points()
    # and so on

This is the floor-level -- the way Goren counted HCP's
and shape.  Now visit http://www.gg.caltech.edu/~jeff/knr.txt
and see one set of tweaks that can be applied to make
this more accurate.  I have my own ideas, and the end-user
is likely to have his or her own (no two bridge-players agree
on ALL...!-).  Clearly I need to allow "override and call the
overridden method" so no need to COPY AND PASTE (horror!)
all this code is needed.  E.g., one popular tweak would be
to subtract a point for a totally flat hand (4-3-3-3) and add
one for a hand with a very long suit.  With no need to copy
and paste, the user of the framework just needs to code:

class FlatBad_LongGood(SimpleEvaluate):
    def shape_points(self):
        baseval = SimpleEvaluate.shape_points(self)
        shortest = reduce(min, self.suit_lengths)
        longest = reduce(max, self.suit_lengths)
        if shortest>2: baseval -= 1
        if longest>6: baseval += 1
        return baseval

And meanwhile, another popular tweak is liking aces:

class AceIsNice(SimpleEvaluate):
    def high_card_points(self):
        baseval = SimpleEvaluate.high_card_points(self)
        aces = self.card_ranks.count(14)
        if aces==0: baseval-=1
        elif aces==4: baseval+=1
        return baseval

So how does another use COMBINE both of these behavioral
tweaks?  *COPY AND PASTE*?!

The *OBVIOUS* way, of which I STILL have seen no hint
at all from you why it should be AT ALL 'bad' in Python:

class SmartEvaluate(AceIsNice, FlatBad_LongGood):
    pass

That's it -- period!  When the user in his or her scripts
needs the D+H (distribution+honor) points, he or she
just calls self.dh_points(), and inheritance and overrides
ensure the polymorphic call will just do the right thing.

*WHAT ADVANTAGE DO YOU ASSERT* that would make
it worthwhile to have the user start coding delegation
and search-boilerplate, etc, etc, to duplicate all that the
Python interpreter is ALREADY giving him/her for free?!


> from A import *
> from B import *
> ...
> from X import *
> 
> applied at the class level.

It's chaining of dictionaries, not .update calls as this
technique would do.  Not that there's anything that is
intrinsically bad in doing a clever series of .update calls
on a dictionary, but a typical override (depending on
the field of application) may have to call the method
that is being overridden, and .update and equivalents
don't support that as well as dict-chaining does.


> BTW, is there any book or other source which explains
> OOP python-wise?

I think Mark Lutz' 2nd edition of Programming Python
may be one answer to this question.  But no, as far as
I know (and I should), there is no Python equivalent of
such books as "Object-Oriented Software Construction",
"The Smalltalk Design Pattern Companion", Fowler's
"Refactoring", and so on.  Yes, there SHOULD be an
"Object-Oriented Programming Through Python" or the
equivalent.  The Cookbook chapter on OO (when the
Cookbook comes out... don't hold your breath:-) may
help, though it will be mostly concrete snippets of
code _illustrating_ issues, concerns, techniques, and
actual applications, rather than general-purpose design
level considerations (do start by peeking at the current
early state of the Cookbook on the ActiveState site... all
are invited to participate, so, why not offer a recipe that
shows the huge advantages you claim can be had by
eschewing multiple inheritance?-).


Alex



_________________________________________________________
Do You Yahoo!?
Get your free @yahoo.com address at http://mail.yahoo.com





More information about the Python-list mailing list