[Python-3000] pep 3124 plans

Phillip J. Eby pje at telecommunity.com
Sat Jul 21 20:16:57 CEST 2007


At 10:55 PM 7/20/2007 -0700, Talin wrote:
>You mentioned earlier that there was a design reason for preferring
>@overload and @when vs. the earlier RuleDispatch syntax, but the
>explanation you gave wasn't very clear (to me anyway).
>
>(I personally prefer the @somegeneric.overload, but that's purely an
>aesthetic value judgement - if there's a strong architectural advantage
>of the other syntax, I'd like to hear it.)

You can't add new method combinations that way.  If method combining 
is a function, not a method, then you can add as many new method 
types as you like.  If you have to use @somegeneric.before and 
@somegeneric.after, you can't decide on your own to add @somegeneric.debug.

However, if it's @before(somegeneric...), then you can add @debug and 
@authorize and @discount and whatever else you need for your 
application, without needing to monkeypatch them in.

To me, TOOOWTDI means that all (or nearly all) the decorators should 
follow the same pattern.


>Right. There are two reasons that I think that post-hoc overloading runs
>into problems. The first, as you mentioned, is that it's difficult to
>implement without some kind of trickery.

Well, that depends on what you define as "trickery", but clearly 
Guido feels that being able to overload an existing function without 
having to go through the code of every possible client is indeed "trickery".

IMO, however, going through the code of the clients is an 
unreasonable and unscalable task that goes against the whole point of 
the exercise: to "assert qualified statements over oblivious code" 
(one common definition of aspect-oriented programming).  If I have to 
go through all the code that might have imported the function and 
stored it somewhere, that's hardly oblivious.  It creates an 
opportunity for invisible, *import sequence-dependent* bugs, that can 
be reintroduced any time somebody changes an import statement!

So the irony, IMO, of avoiding this "trickery" is that it makes the 
practice error-prone, thereby providing a self-fulfilling 
justification for avoiding its use.  (Whereas, if the "trickery" were 
allowed, it would be much safer to actually use it.)

All that having been said, I'm still willing to make an 
implementation that does it Guido's way.  I just don't agree that the 
restriction is justified.  But more on that below.


>The second reason - this is my opinion - is that it too much resembles
>the mythical "comefrom" statement (the opposite of "goto"). The
>"comefrom" statement is intended to be a joke - the worst possible
>language feature from the standpoint of being able to manually trace the
>flow of execution of a program.

Well, I've worked with people who dislike OO for exactly the same 
reason, since they feel they can never know whether a method might 
have been overridden in a subclass.  Seriously!

However, for the specific use cases *I* have in mind, you'd be using 
oblivious extension to implement customer-specific business rules, 
layered atop a core framework.  You don't want to waste time 
declaring *everything* overloadable, any more than you declare 
classes to be subclassable!  You just need to be able to write the 
customer's rules in one place.  So if you're trying to follow 
something manually, you're going to look at that customer's business 
rule modules in order to know about the exceptional control flow.

I don't think that's really comparable to the joke implementation of 
"come from".  In any system, the more the computer does for you, the 
harder it will be for you to mentally emulate what the computer's 
doing, step-by-step.  That's simply the nature of the beast.

However, in the case of rule-based declarative abstractions, you're 
getting closer to something that's *easier* for the brain to 
model.  Our brains run by pattern recognition, with more-specific 
patterns taking precedence, so this is an easier model for your brain 
to follow than step-by-step computation anyway.  Certainly, it's an 
easier model for your software customers to provide you with in the 
first place.

I.e., customers usually don't give you a step-by-step, "well, first I 
check if the customer has an outstanding balance before I ship them 
anything."  They say, "Don't ship stuff to people with an outstanding balance."

And guess what?  Viewed formally, that's a "come from" statement.

So the most straightforward expression of typical business rules and 
requirements, is going to consist of a list of come-froms.  So coding 
them that way actually gets us more verifiable requirements, and a 
simpler mental model to *produce* the code in the first place.


>One issue that hasn't been satisfactorily resolved is the handling of
>the 'self' parameter. At least, let me give my explanation of what I
>think the issue is and see if we're on the same page:
>
>Overloading a class method requires special treatment of the 'self'
>parameter because there's an implicit constraint on what types of
>objects can be passed as 'self': for any method defined in any class,
>the 'self' parameter must be an instance of the class (or a subclass) in
>which the method is defined. Now, this would be trivial if we required
>the programmer to explicitly declare the type of 'self', but this
>violates DRY and has the potential to cause mischief if the programmer
>forgets to update the method signature when they change the class.

Well, actually that never occurred to me, because obviously you can't 
do that (refer to the class before it's finished being defined).  :)


>If it turns out that there's no way to get a callback when the class has
>finished being built, then we may have to defer finishing the
>construction until the first time the generic function is called. This
>wouldn't be too bad, considering that there's a bunch of other stuff
>that is lazily calculated on first call anyway, from what I understand.

Actually, this isn't anywhere near as complicated as all the stuff I 
just snipped from the above.  :)  All that matters is whether the 
decorator is invoked in the body of a class.  If it is, it needs a 
callback to finish the job.  If it isn't, it can immediately go ahead 
with what it's doing.

Note that this was implemented in RuleDispatch literally years ago; 
it's only the loss of __metaclass__ that presents a problem for a 
Py3K implementation.



More information about the Python-3000 mailing list