[Python-3000] PEP 3124 - Overloading, Generic Functions, Interfaces, etc.

Phillip J. Eby pje at telecommunity.com
Thu May 10 03:23:41 CEST 2007

At 06:26 PM 5/9/2007 -0400, Jim Jewett wrote:
>On 5/9/07, Phillip J. Eby <pje at telecommunity.com> wrote:
>>At 09:54 PM 5/9/2007 +0200, BJörn Lindqvist wrote:
>> >What if they have defined a do_stuff that dispatch on ClassC that is a
>> >subclass of ClassA? Good luck in figuring out what the code does.
>> >With the non-overloaded version you also have the ability to insert
>> >debug print statements to figure out what happens.
>>      @before(do_stuff)
>>      def debug_it(ob: ClassC):
>>          import pdb
>>          pdb.set_trace()
>I think this may be backwards from his question.  As I read it, you
>know about class A, but have never heard about class C (which happens
>to be a substitute for A).  Someone added a different do_stuff
>implementation for class C.
>    @before(do_stuff)
>    def debug_it(obj: ClassA):    # Never called, it is a classC

Actually, if you read what was said above, ClassC is a subclass of 
ClassA, so the above *is* called.

>    def debug_it(obj: not ClassA)   # can't do this?

Actually, you can, if you create something like a NotClass type and 
register methods to define its implication relationships to classes 
and other criteria.  Of course, it then wouldn't be called for ClassC...

>    def debug_it(obj):                # OK, trace *everything*.
>        # Or, at least, everything that nicely did a call_next_method,
>        # in case you wanted to wrap it this way.  Objects that thought
>        # they were providing a complete concrete implementation will
>        # still sneak through

Which is an excellent demonstration, by the way, of another reason 
why before/after methods are useful.  They're all *always* called 
before and after the primary methods, regardless of how many of them 
were registered.

>    def wrap_the_generic(generic_name, debug_it):
>        orig = generic_name
>        def replacement( ...)  # hope you get the .sig right
>            debug_it(...)
>            orig(...)
>        generic_name = replacement   # hope you can monkeypatch
>        # uhh ... was the original supposed to have additional behavior,
>        # for more registrations, etc...

I don't understand what this last example is supposed to be, but note 
that if you want to create special @debug methods with higher 
precedence than Around methods, it's relatively simple:

    class Debug(Around):
        """Like an Around, but with higher precedence"""

    debug = Debug.make_decorator('debug')
    always_overrides(Debug, Around)
    always_overrides(Debug, Method)
    always_overrides(Debug, Before)
    always_overrides(Debug, After)

(It occurs to me that although the current prototype implementation 
requires you to explicitly declare method override relationships for 
all applicable types, I should probably make the transitive 
declaration(s) automatic, so that the above would require only 
'always_overrides(Debug, Around)' to work.)

>Unless I'm missing something, this only simplifies things when all
>specific implementations not only drink the kool-ade, but avoid
>kool-ade related bugs.

I don't understand what you mean here.

More information about the Python-3000 mailing list