[Python-3000] pep 3124 plans (original) (raw)
Phillip J. Eby pje at telecommunity.com
Tue Jul 24 03:39:17 CEST 2007
- Previous message: [Python-3000] pep 3124 plans
- Next message: [Python-3000] pep 3124 plans
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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:
It's hard to see
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.
- Previous message: [Python-3000] pep 3124 plans
- Next message: [Python-3000] pep 3124 plans
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]