[Python-3000] pep 3124 plans

Phillip J. Eby pje at telecommunity.com
Mon Jul 30 22:10:08 CEST 2007


At 12:20 PM 7/27/2007 -0400, Phillip J. Eby wrote:
>At 08:25 AM 7/27/2007 -0700, Guido van Rossum wrote:
> >Basic GFs, great. Before/after/around, good. Other method
> >combinations, fine. But GFs in classes and subclassing? Not until we
> >have a much better design.
>
>Sounds reasonable to me.  The only time I actually use them in
>classes myself is to override existing generic functions that live
>outside the class, like ones from an Interface or a standalone generic.
>
>The main reason I included GFs-in-classes examples in the PEP is
>because of the "dynamic overloading" meme.  In C++, Java, etc., you
>can use overloading in methods, so I wanted to show how you could do
>that, if you wanted to.
>
>I suspect that the simplest way to fix this in Py3K is with an
>"overloading" metaclass, as it would not even require any
>decorators.  That is, you could provide a custom dictionary that
>records every definition of a function with the same name.  The
>actual metaclass creation process would check for a method of the
>same name in a base class, and if it's generic (or the current class
>added more than one method), put a generic method in.
>
>With a little bit of work, you could probably determine whether you
>could get away with dropping the genericness in a subclass;
>specifically, if all the subclass-defined methods are "more specific"
>than all base class methods, then there's no need for them to be in
>the same generic function, unless they make next_method calls.  Thus,
>you'll end up with normal methods except where absolutely necessary.
>
>Such a metaclass would make method overloads look pretty much the
>same as in OO languages with static overloading.  The only remaining
>hole at that point would be reconciling super() and next_method.  If
>you're using this metaclass, super() is only meaningful if you're not
>in the same generic function as is used in your base, while
>next_method() is only meaningful if you *are*.
>
>I don't know of any quick way to fix that, but I'll give it some thought.

I think I see how to resolve next_method() and super() now: if you 
create a new GF in a subclass, you just define its default_action to 
be something that calls super().  Then, you just use next_method() 
instead of super().

Currently the default default_action is a NoMethodFound action, but 
replacing it for a given GF is a piece of cake.  So, an "overloading" 
metaclass could be written that would:

1. Use __prepare__ to catch multiple function assignments to the same 
name, converting them to overloads

2. Decide whether to combine those overloads with an existing generic 
in the base classes, or to create a new generic and chain it with a 
super() default action.

3. Automatically make the class object part of the overload 
registrations for 'self'.

The principle downside to this approach is that only one metaclass 
can provide a __prepare__ dictionary, which means it's even more 
difficult to combine metaclasses than it is in today's Python -- 
which means I want to give a little more thought to PEP 3115, to see 
if there is any way to at least emulate the "derived metaclass rule" 
for __prepare__, that Python currently enforces for the base classes.

In other words, a class' metaclass has to be a derivative of all its 
bases' metaclasses; ISTM that a __prepare__ namespace needs to be a 
derivative in some sense of all its bases' __prepare__ results.  This 
probably isn't enforceable, but the pattern should be documented such 
that e.g. the overloading metaclass' __prepare__ would return a 
mapping that delegates operations to the mapping returned by its 
super()'s __prepare__, and the actual class creation would be 
similarly chained.  PEP 3115 probably needs a section to explain 
these issues and recommend best practices for implementing 
__prepare__ and class creation on that basis.  I'll write something 
up after I've thought this through some more.

But I think this wraps up the overall question of *how* to integrate 
methods and GFs in a way that supports a more C++/Java-like 
overloading style (i.e., no decorators on individual overloads within 
a class).  The main drawback is that it's a silent error if you leave 
off the metaclass.

Another option of course would be to make this part of the default 
metaclass, but that would bring in the issue of needing a standard 
API (and default implementation) for GF's.

In the meantime, though, it's nice to see a practical application for 
PEP 3115 -- i.e., implementing transparent Java-style 
overloading.  It's absolutely not possible in 2.x without decorators, 
both because of the lack of argument annotations and the lack of a 
__prepare__-controlled class-suite namespace.



More information about the Python-3000 mailing list