extending methods ?

Alex Martelli aleax at aleax.it
Wed Oct 1 11:42:34 EDT 2003


Arnd Baecker wrote:
   ...
>> A matter of opinion.  I find it much nicer to know that a
>> local variable is local, and an instance variable is not.
> 
> I absolutely agree. And that's why I wrote the (non-existing)

Let me put it another way: I find it much nicer that LOCAL
variables are a LOCAL issue of the function using them, and
NO other function can possibly ever know anything about them
(excepting debuggers & the like).  For your idea to work,
local variables would have to NOT be LOCAL issues -- they
would have to be somehow known OUTSIDE the function.


> Now, why could something like this be useful:
> I have a situtation of a class with several methods
> and now I would like to extend this class by
> adding a few lines to each of the methods.

Think of it another way: a function is a black box.  Make
believe that you DO NOT know the exact source code with
which the function is currently implemented, e.g. such
details as what names are internally, LOCALLY used for its
LOCAL variables.  Is your desired approach even CONCEIVABLE
in such a worldview?  It appears to me that it isn't; and
thus, that you desire a worldview where such boundaries as
"inside" vs "outside" a function cannot really exist.  I
strongly believe that removing such boundaries would be an
utter disaster, leading to totally unmaintainable code; i.e.,
that such boundaries are STRONGLY desirable.

> These further lines would make use of the variables defined
> in the original methods.
> An extension in this way would not require to
> change anything in method1 of class_A
> and any changes made in class_A carry over directly to
> class_B.
> (In a sense one could see this "copy" similar to a
> "pre-processor" step  ...).

Good analogy.  The preprocessor of C is a good contender for
its single most error-prone feature; C++ has been fighting
long and hard to wipe it out (though for backwards compatibility
reasons it will never entirely succeed).  Reason #1 for the
preprocessor being such a health hazard is that it's no
respecter of SCOPE -- it doesn't know nor care what is LOCAL
to WHERE.

You are claiming that "any changes made in class_A carry over 
directly" -- but you seem to miss that, in your proposal,
changes that are normally totally innocuous, because they
are guaranteed to be isolated from the outside, would instead
"carry over directly" *AND DESTRUCTIVELY* to subclasses that
made use of your innovation.  I.e., the base class would
suddenly become constrained in such intimate implementation
details as *THE NAME OF LOCAL VARIABLES* (not to mention
many other CURRENTLY-LOCAL implementation details of methods).
***The base class would become totally dependent, down to
minute details of its implementation, on which of those
details happen to be exploited by its subclasses***.  Good
bye, therefore, to the "open/closed principle" (google it up)
and with it to just about every substantial advantage of
object-oriented programming.  *SHUDDER*.


> Instead of the above (which does not exist, and I'd guess never will ;-)

I earnestly hope and pray and trust it never will.

> one could
>   a) Invoke the superclass' method  in which all the
>      relevant variables needed for the method in class_B are defined
>      as self.<variable_name>. And then they can be
>      accessed in class_B.

Of course!  If the superclass CHOOSES, as part of its interface, to
expose certain variables as instance attributes, then it's PERFECTLY
SENSIBLE to access them in subclasses.

>   b) Take a verbatim copy of class_A
>      and just add the additional lines at the end
>      of the corresponding methods.

Such "copy and paste reuse" is generally a disaster waiting to
happen -- albeit in a longer time horizon than your proposal would
be -- because modifications to the original do not "propagate" once
a copy is made, so functionality may "drift" among copies (and it
generally does).  Such a "solution" should only be considered if
the base class was badly designed for the subclass's needs AND if
it was a worse choice to modify (redesign) the base class -- for
example, the base class comes from somebody else's package, and
does not offer sufficient granularity of customizability for your
current needs.  Then, you do need to entirely override certain
methods, reimplementing them from scratch -- one strategy for such
reimplementation is, in fact, to start with A's current choices
of implementations, and edit them as appropriate.  But once you
are having to reimplement anyway you might be better advised to
consider, as long as you're at it, implementing strategy [A] --
redo the base class ONCE by supplying it with the amount of
flexibility (and granularity within the flexibility) that you do
now in fact know you need; "actual" subclasses can then all be
coded sensibly.

>      The drawback here is that any code changes
>      in the common parts of the methods in class_A and class_B
>      have to be applied in both parts.

Yes, that is indeed the downside of "copy and paste reuse".


> So for b) it is the code duplication which I don't like
> and for a) I don't like too much that one has to make
> all the variables accessible self.<variable_name>=....
> This adds a bunch of code which is only used when class_A
> is subclassed.

What "bunch of code"?!  Accessing, e.g., self.x is exactly
as much code as accessing a bare x would be -- one expression
or statement, direct and immediate 1:1 correspondence.

> (Of course  there is still option c) to write a small
> python programm which takes class_A and does a "copy-and-paste"
> operation at the corresponding places in class_B.)
> 
> Personally I tend to a) or c) ;-)
> But maybe there is a better way of doing the above?

Designing your classes AS CLASSES rather than as bunches of
vaguely related snippets of source would undoubtedly be a
far better way to proceed.  But if you keep presenting a
problem as you do, I can't give any suggestions on how the
design should be.  Try this thoughtexperiment: imagine your
fairy godmother put a spell on you making it IMPOSSIBLE for
you to SEE the *sources* of the base class.  You can ONLY see
the INTERFACE of the base class -- you have complete knowledge
of WHAT each method does (in particular, what instance variables
it uses and/or affects), but NO knowledge whatsoever of HOW it
does it, internally.  Would your ACTUAL problem then become 
totally insoluble?  I very much doubt it.  So, CAN you perhaps
present your ACTUAL problem -- WITHOUT any reference to the
INTERNAL source details of the existing baseclass...???

That you CAN in fact see how the sources "happen" to be may
be blinding you to the actual problem.  "Information hiding"
was invented for a good reason -- sometimes, seeing more info
than you actually SHOULD see makes your problem HARDER to
express and solve effectively.  So, learning to selectively
"UN-SEE" some of the information you "happen" to have is an
important trick to learn.

> [ ... speed part snipped - many thanks I learned a lot!]

You're welcome.  But speed is hardly ever the overriding issue
in programming (Knuth guesstimated that we should ignore
micro-optimizations "maybe 97% of the time", if I recall
correctly -- and in today's application programming it may
be even more often...:-).


Alex





More information about the Python-list mailing list