[Python-Dev] PEP 443 - Single-dispatch generic functions

Steven D'Aprano steve at pearwood.info
Fri May 24 12:53:54 CEST 2013

On 24/05/13 15:09, Nick Coghlan wrote:
> On Fri, May 24, 2013 at 8:40 AM, Steven D'Aprano <steve at pearwood.info> wrote:
>> I don't think that they will. Being able to register multiple types with a
>> single call reads very naturally to me, while multiple decorators still
>> looks weird. Even after many years of seeing them, I still get a momentary
>> "What the hell...?" moment when I see two decorators on one function. That's
>> only going to be increased when both decorators are the same (apart from the
>> argument). The double decorator form above looks to me as weird as:
>> x = func(a)
>> x = func(b)
>> would. I have to stop and think about what is going on, and whether or not
>> it is a mistake.
> The difference is that this idiom quickly becomes familiar and unexceptional:
>      @fun.register(float)
>      @fun.register(Decimal)
>      def fun_floating_point(arg1, arg2):
>          ...

I initially wrote a reply about the nature of ambiguity, why register(float, Decimal) should not be considered ambiguous, why stacked decorators that are near-duplicates are a code smell, blah blah blah. But for the sake of brevity I'm going to skip it. The important point that you make is here:

> Is that multiple dispatch? Or is it registering for single dispatch on
> multiple different types?
> Sure, we could pick the latter meaning for the standard library, but
> existing generic function implementations (cited in the PEP) use the
> tuple-of-types notation for multiple dispatch.

This is an excellent point I had not considered.

By the way, it seems to me that Guido's multimethod implementation referenced in the PEP actually uses a single decorator argument per function argument, not a tuple-of-types:

@multimethod(int, int)
def foo(a, b):
     ...code for two ints...


You have convinced me: ambiguous or not, for the sake of future expansion I agree that multiple positional arguments to the register method should be left for some hypothetical multiple-dispatch generics:

@fun.register(float, Decimal)  # not yet supported, but maybe someday

would mean "first argument is a float, second argument is a Decimal".

But that still leaves open how to specify single dispatch on more than one type:

> stacking registration decorators is
> just a new idiom to become accustomed to.

Python built-ins and the standard library already have a standard idiom for specifying multiple values at once. A tuple of types is the One Obvious Way to do this:

@fun.register((float, Decimal))

which matches the same standard idiom that should be familiar to most people:

isinstance(obj, (float, Decimal))
issubclass(cls, (float, Decimal))

And of course it is forward-compatible with our hypothetical future multiple-generics.


More information about the Python-Dev mailing list