[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