[Python-3000] pep 3124 plans

Phillip J. Eby pje at telecommunity.com
Tue Jul 24 03:39:17 CEST 2007


At 12:54 PM 7/24/2007 +1200, Greg Ewing wrote:
>Phillip J. Eby wrote:
> > And that is in fact the *normal* case, even in GF use.  You seem to be
> > arguing that possible == probable, when it simply ain't so.
>
>No, I'm saying that it's hard to convince myself that I'm
>not going to fall into one of the possible traps, even if
>it's an improbable one.
>
>When adding an overload to a GF, what methodology can I
>follow to ensure that my overload doesn't interact in an
>unfortunate way with another one somewhere else, perhaps
>one not written by me?

What methodology can you follow that ensures that same thing when 
overriding a method in a subclass?


> > Yeah, and a program *can* be full of monkeypatching and change classes'
> > __bases__ at runtime, but most people don't write their code that way,
> > most of the time.
>
>The difference is that we're talking about a system
>specifically *designed* for carrying out monkeypatching.
>I don't care what you call it, it still looks like
>monkeypatching to me.

You're not looking very hard, then.  Is this excerpt from 
peak.rules.core monkeypatching?

def implies(s1,s2):
     """Is s2 always true if s1 is true?"""
     return s1==s2

from types import ClassType

when(implies, (type,      type)     )(issubclass)
when(implies, (ClassType, ClassType))(issubclass)
when(implies, (type,      ClassType))(issubclass)

when(implies, (bool, bool))(lambda c1, c2: c2 or not c1)
when(implies, (bool, object))(lambda c1, c2: not c1)
when(implies, (object, bool))(lambda c1, c2: c2)

To me, this looks like a straightforward explanation of the 
implication rules between new-style and classic classes and boolean 
values.  In fact, it seems much more straightforward to me, than 
writing out a big if-then tree whose *intent* I would have to discern 
from comments or the structure of the tree itself.

And if I had to discern the intent from the structure of the if tree, 
I would have no way of knowing whether the if's as written were in 
fact *correct*.  I could mistake a bug for the author's intention in that case.

This is just one of the ways in which generic functions can be a 
superior tool for code understanding -- even in the complete absence 
of anything that can be described as "monkeypatching".

In truth, every interface or abstract base class is just another way 
of specifying a generic function.  When you say that objects 
implementing a certain interface or protocol must have a 'foo' 
method, then any subclass may add a new *actual* implementation of 
'foo' -- which is no different from adding a method to a generic 
function for a new type.


>  The fundamental reason that
>we think monkeypatching is a bad idea is still there --
>something done by one part of the program can affect
>the behaviour of another part with no obvious connection.

It's FUD to try to associate monkeypatching with GF's.  Generic 
functions have *none* of the bad effects of monkeypatching.

Monkeypatching is bad because:

1. It's hard to see

2. Can't be safely composed (i.e. multiple monkeypatches) without 
introducing dependency order at best and bugs at worst

GF method additions are highly visible, and are safely composable, 
since more-specific methods override each other, and only truly 
independent methods can "float" as to execution order.


> > The whole point of GF's is that they make things
> > *simpler*,  because you can usually avoid the sort of awkwardness that
> > accompanies trying to do those things *without* GF's.  (E.g. adapters,
> > registries, and the like -- which are just as hard to analyze statically.)
>
>Yes, but as far as I can see, GFs don't make these things
>much *easier* to analyse statically. Registries are awkward
>because of that difficulty, not because they're hard
>to implement.
>...
>Yes, which is largely why I've personally never used super(),
>and regard it as a misfeature. I wouldn't mind if it went
>away completely.
>...
>Even once I've got such a list, I've then got to examine it
>carefully and try to nut out the implications of all the
>type relationships, before/after/around/discount/etc method
>cominations, and whathaveyou.
>...
>Yes, I know you already get some of this with multiple
>inheritance -- which is why I use it very rarely and very
>carefully. Also the complexities tend to be confined to the
>class doing the multiple inheriting and only need to be
>considered by the author of that class, not everyone who
>uses it.

Okay, well I guess the above statements all put you squarely in the 
"OO is too scary" category, so I'm not sure there's much else I can 
say that'd be useful.

Keep in mind, however, that without a *standard* way of doing GF's, 
you will have to figure out *each* library or program's ad-hoc 
workarounds, instead of simply getting to know One Obvious Way of doing it.


>And what if the program doesn't exist yet, because I'm
>still thinking about how to write it? Or it exists but
>isn't yet in a state where it can be run successfully?

I don't understand what you're asking, here.


>  > binary operators depend on multiple argument values (and you
> > have to know *both* types in order to work out the result)
>
>Yes, that can be a bit more complex, but at least the method
>that gets called has to belong to one class or the other.
>Also it's easier to follow nowadays with the auto-coercion
>system being phased out -- the left operand gets first say,
>and if it doesn't care, the right operand gets its say.

Oh really?  Are you sure about that?  I was under the impression that 
under certain circumstances, if one object is "more specific" than 
the other (i.e., one is an instance of a subclass of the other's 
type), then that one gets first say.



More information about the Python-3000 mailing list