[Python-3000] Parameter types and multiple method dispatch
Collin Winter
collinw at gmail.com
Thu Jul 20 20:22:51 CEST 2006
On 7/20/06, Talin <talin at acm.org> wrote:
> However, in order to use type annotations, one needs to associate
> between the actual arguments and the formal parameters - because the
> annotations are keyed by the formal parameter they are attached to. One
> way to do this is to simulate the mapping of arguments to formal
> parameters within the decorator. Once you know which formal parameter a
> given value is assigned to, you can then retrieve the annotation for
> that parameter and apply it to the value.
>
> However, there are a number of drawbacks to doing this - first, the
> mapping algorithm isn't really that simple in the general case. Worse,
> the assignment of arguments to formal parameters is a prime suspect in
> the relative 'slowness' of Python function calls compared to other
> language features - and in order for the decorator to figure out which
> argument goes with which formal parameter, the decorator is now forced
> to perform that same mapping *again*.
[snip]
> A different possibility is to attempt to do the mapping in reverse -
> that is, for a given formal parameter (and its associated type
> annotation), attempt to determine which input argument corresponds to
> that parameter.
>
> The problem with this notion is that the parameter mapping algorithm is
> an iterative one - it would be difficult to come up with an algorithm
> that does Python parameter assignment *in reverse*, that was guaranteed
> to be correct for all possible edge cases.
I've implemented both solutions before, and neither proved to be all
that difficult (after actually reading the manual, that is ; ) Also,
I'm not sure what you're considering to be 'the general case', but I
remember from my own adventures in this area that the most frequent
function types were "def foo(a, b, c)"-style functions, ie, functions
with only positional arguments. In this case, the mapping becomes dead
simple.
> By saying that annotations have no fixed meaning, what we're really
> saying is that there's no "standard interpretation" of these
> annotations, and that's where IMHO the trouble lies. If there's no
> standard interpretation, then everyone is going to interpret them
> differently. A function with more than one independently-written
> decorator is going to have problems, each decorator trying to pick out
> the parts of the annotations that's meant for them and not the others.
Guido and I went back and forth on this for a while, whether or not to
include a "standard interpretation" with Python itself. We're counting
on the shear complexity of implementing an annotation-interpreting
library to keep the number of these libraries low and in the hands of
people who know what they're doing.
> It seems to me that a better solution is to allow the *decorators* to
> have function signatures. For example:
>
> @overload(int,int)
> def add(a,b):
> ...
>
> The advantage of this is twofold:
[snip]
> Second, it means that the mapping problem hasn't entirely gone away, but
> has somewhat been reduced, because now the type annotations are
> referring to the *wrapper function's* arguments, not the arguments of
> the wrapped function. This means that the wrapper is now on the
> 'inside', and can see all of the variables in their mapped configuration.
Huh? Unless you have a raft of decorators for every possible
permutation of function parameters, you've probably written that
overload() decorator to have a signature of "def overload(*vargs)" or
"def overload(*vargs, **kwargs)", in which case you still have to do
the argument -> formal parameter mapping.
> Of course, there is still the problem of passing the arguments to the
> inner function - but that's no worse than the problem that decorators
> have today.
I don't understand; what kind of decorators do you write that have this problem?
> For example, '@overload(int,int,a=int)' doesn't express the notion that a is
> a keyword argument that should be constrained to an int value.
It certainly can express that if you want it to. Just use **kwargs in
the decorator to catch all keyword arguments and then treat them
differently.
Collin Winter
More information about the Python-3000
mailing list