coady / multimethod

Multiple argument dispatching.
https://coady.github.io/multimethod
Other
277 stars 24 forks source link

supporting named arguments #28

Closed cunningjames closed 3 years ago

cunningjames commented 3 years ago

Right now this results in a dispatch error, because dispatch is based only on unnamed arguments:

@multimethod
def f(foo: str):
    return foo

f(foo="bar")
# => DispatchError: ('f: 0 methods found', (), [])

Not a huge deal, but some people are rather particular about using named arguments whenever possible. Would this be possible to support?

This would complicate the dispatch algorithm, admittedly. You'd have to keep track of argument names for each overload and, accordingly, rearrange *args / **kwargs in multimethod.__call__(). This could get a bit gross when accounting for argument names that are repeated or arranged in different orders for different overloads ...

coady commented 3 years ago

I think any linear scan of the registered functions is off the table, because it's so slow and overload already does that. There is the possibility of using inspect.Signature.bind once to get the positional arguments for use in dispatch. That would require having a definitive signature, and would still be slower. In my testing with a single argument it would be about 5x slower than the current implementation, which is on par with functools.singledispatch.

Which reminds me of discussion #12, because another oddity about singledispatch is that it effectively requires a base implementation with no annotations (which is to say it ignores them). That could be an elegant way for a user to indicate that they're willing to take the performance hit, by providing the definitive signature needed anyway.

So it would look like:

@multimethod
def f(foo):
    pass

@multimethod
def f(foo: str):
    return foo

f(foo="bar")
coady commented 3 years ago

Another concern is that singledispatch requires positional arguments.