On 24/05/13 15:09, Nick Coghlan wrote:
On Fri, May 24, 2013 at 8:40 AM, Steven D'Aprano <steve@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... http://www.artima.com/weblogs/viewpost.jsp?thread=101605 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. -- Steven