plum icon indicating copy to clipboard operation
plum copied to clipboard

Can't use @dispatch on methods with types inheriting from Generic

Open rupert-madden-abbott opened this issue 4 years ago • 5 comments

Simple example:

from typing import TypeVar, Generic

from plum import dispatch

T = TypeVar('T')


class FooBar:
    pass


class Foo(Generic[T]):
    pass


class Bar:
    def __init__(self):
        pass

    @dispatch
    def some_method(self, foo: Foo[FooBar]):
        pass


Bar().some_method(Foo())

This will fail with an error as follows:

line 420, in ptype
    raise RuntimeError(f'Could not convert "{obj}" to a type.')
RuntimeError: Could not convert "__main__.Foo[__main__.FooBar]" to a type.

Is this functionality missing or do I need to add any more assistance in for plum to get this working?

rupert-madden-abbott avatar Sep 17 '21 14:09 rupert-madden-abbott

Hey @rupert-madden-abbott,

Thanks for opening an issue!

The simple example that you give works for me:

from typing import TypeVar, Generic
from plum import dispatch


T = TypeVar('T')


class Bar(Generic[T]):
  pass


class Foo:
    @dispatch
    def some_method(self, bar: Bar):
        print("Let's go!")
>>> a = Foo()

>>> b = Bar()

>>> a.some_method(1)
NotFoundLookupError: For function "some_method" of __main__.Foo, signature Signature(__main__.Foo, builtins.int) could not be resolved.

>>> a.some_method(b)
Let's go!

Might you not be on the latest version, or perhaps running a subtly different example?

wesselb avatar Sep 17 '21 18:09 wesselb

@wesselb my apologies, the example I gave was not right. I have updated with an example that does fail.

Crucially, my example was failing to supply a type parameter for Bar when it was specified as the type of the parameter.

I've tested the new snippet and verified that it does produce an error.

For information, this is on version 1.5.4

rupert-madden-abbott avatar Sep 17 '21 19:09 rupert-madden-abbott

No problem at all! I figured that the example was missing something.

Unfortunately, this usage of typing is not (yet) supported by Plum. Plum, however, does offer a construct called parametric types, which you can use to achieve the same thing:

from plum import parametric, dispatch


class FooBar:
    pass


@parametric
class Bar:
    def __init__(self, x):
        self.x = x

    @classmethod
    def __infer_type_parameter__(cls, x):
        return type(x)


class Foo:
    @dispatch
    def some_method(self, bar: Bar[FooBar]):
        print("Let's go!")
>>> Foo().some_method(Bar(FooBar()))
Let's go!

>>> Foo().some_method(Bar(1))
NotFoundLookupError: For function "some_method" of __main__.Foo, signature Signature(__main__.Foo, __main__.Bar[<class 'int'>]) could not be resolved.

I realise that it would be super convenient to fully support all features of typing, but that's a work in progress.

wesselb avatar Sep 17 '21 19:09 wesselb