beartype / plum

Multiple dispatch in Python

Home Page:https://beartype.github.io/plum

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`Union[type[...], ...]` and `type` not the same as `type[...]`, `...`, and `type`

sylvorg opened this issue · comments

Hello!

With the following code:

from plum import dispatch
from typing import Union

class Test: pass

test = Test()

@dispatch
def a(testing: Union[type[Test], Test]):
    print(Union[type[Test], Test])

@dispatch
def a(testing: type):
    print(type)

@dispatch
def b(testing: type[Test]):
    print(type[Test])

@dispatch
def b(testing: Test):
    print(Test)

@dispatch
def b(testing: type):
    print(type)

b(Test)
b(test)
a(Test)
a(test)

a is giving me an AmbiguousLookupError:

Traceback (most recent call last):
  File "/mnt/wsl/sylvorg/sylvorg/sylveon/siluam/oreo/./test23.py", line 33, in <module>
    a(Test)
  File "/nix/store/04jyrbixnk1n5c5cn1lcv6p1j98nmwxf-python3-3.11.8-env/lib/python3.11/site-packages/plum/function.py", line 367, in __call__
    method, return_type = self._resolve_method_with_cache(args=args)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/04jyrbixnk1n5c5cn1lcv6p1j98nmwxf-python3-3.11.8-env/lib/python3.11/site-packages/plum/function.py", line 398, in _resolve_method_with_cache
    method, return_type = self.resolve_method(args)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/04jyrbixnk1n5c5cn1lcv6p1j98nmwxf-python3-3.11.8-env/lib/python3.11/site-packages/plum/function.py", line 310, in resolve_method
    raise e from None
  File "/nix/store/04jyrbixnk1n5c5cn1lcv6p1j98nmwxf-python3-3.11.8-env/lib/python3.11/site-packages/plum/function.py", line 300, in resolve_method
    method = self._resolver.resolve(target)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/04jyrbixnk1n5c5cn1lcv6p1j98nmwxf-python3-3.11.8-env/lib/python3.11/site-packages/plum/resolver.py", line 334, in resolve
    raise AmbiguousLookupError(self.function_name, target, candidates)
plum.resolver.AmbiguousLookupError: `a(<class '__main__.Test'>)` is ambiguous.

Candidates:
   a(testing: typing.Union[type[__main__.Test], __main__.Test])
       <function a at 0x7f992f091300> @ ~/sylvorg/sylveon/siluam/oreo/./test23.py:11
   a(testing: type)
       <function a at 0x7f992f091440> @ ~/sylvorg/sylveon/siluam/oreo/./test23.py:15

Shouldn't Union function the same as separate definitions?

Thank you kindly for the help!

Hey @sylvorg!

Union does not quite function as separate definitions. What's going on here is the following:

type is not a subtype of Union[type[Test], Test], because it is strictly more general than Test. In addition, Union[type[Test], Test] is not a subtype of type, because Test (which matches objects) is not a substype of type (which matches types):

>>> from beartype.door import TypeHint

>>> TypeHint(Union[type[Test], Test]) <= TypeHint(type)
False

>>> TypeHint(Union[type[Test], Test]) >= TypeHint(type)
False

Therefore, neither signature is more specific than the other, so Plum will not automatically narrow it down. If you input matches both signatures, Plum will throw an ambiguity error, as in the above example.