Closed hzhangxyz closed 3 years ago
It seems it is not a very good choice to implement to accepting empty dict as dict[K, V] if there are two kind dict: dict[K1, V1] and dict[K2, V2]
There are following three condition:
currently, multimethod use condition 1 and it seems condition 2 is not easy to implement?(maybe) but it is the behavior how c++ does I don't know whether condition 3 is a good choice.
Good summary, and there's another problematic case. If empty collections are supported, an empty list called on a method with List[float]
and List[int]
would organically raise an ambiguity error.
But what if it's List[bool]
and List[int]
? The existing behavior would default to List[bool]
because issubclass(bool, int)
. It would require a special hack in the dispatch algorithm itself to consider that ambiguous, because that function signature is a total ordering, and therefore ambiguity should be impossible.
So there's a conundrum where the only sensible behavior is likely to be surprising to the average user.
There's a prototype in branch empty to experiment with, but I'm not sure about this. It could just be a limitation of a dynamically typed language.
I suppose you could just fall back on a catchall:
@multimethod
def foo(xs: List[int]): ...
@multimethod
def foo(xs: List[bool]): ...
@multimethod
def foo(xs: List):
# deal with the empty case explicitly
if not len(xs):
return "unknown"
raise TypeError(...)
It'd be cool if Literal[[]]
worked, but the following throws an error:
@multimethod
def foo(xs: Literal[[]]):
return "unknown"
# ~/.pyenv/versions/3.8.5/envs/hacking/lib/python3.8/site-packages/multimethod/__init__.py in __new__(cls, tp, *args)
# 45 origin = getattr(tp, '__extra__', getattr(tp, '__origin__', tp))
# 46 args = tuple(map(cls, getattr(tp, '__args__', None) or args))
# ---> 47 if set(args) <= {object} and not (origin is tuple and args):
# 48 return origin
# 49 bases = (origin,) if type(origin) is type else ()
#
# TypeError: unhashable type: 'list'
The problem is with Literal[...]
is that the dispatch is based solely on types. overload
would have to be used for that.
code:
run and get output
similarly, I cannot pass empty list
[]
intolist[int]