-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Ordering matters for @overload #1270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Yeah, mypy should show the signature of the superclass method. Also, mypy could perhaps allow you to switch the order of overload variants in case the signatures aren't overlapping, though this is a little questionable as the order could plausibly affect which overload gets picked in a call. |
@JukkaL - what do you mean by "switch the order of overload variants"? Is there some obvious natural ordering that I'm missing? |
By order of overload variants I mean the textual order of the
Mypy generally picks the first overload variant that matches the argument types when type checking a call. If you change the ordering of variants in a subclass the inferred return type could arbitrarily change for a call depending on whether the receiver type is the base class or the subclass, which is undesirable. However, this is a pretty marginal thing in practice. |
Interesting... it wasn't even clear to me that there was a defined order. I had somehow imagined that all overloaded methods would have different (non-overlapping) signatures and therefore order wouldn't matter. Since Python itself doesn't have overloaded functions, the semantics of this was not clear from the examples in the tutorial. |
The reason that there is an order is partially an accident of history, as earlier versions of mypy actually let you use
We could have this overloaded signature in a stub file:
Now if we call |
(Perhaps also relevant to this discussion is the idea that two
unrelated user-defined classes A and B are considered potentially
overlapping because someone might use multiple inheritance to derive a
class from both of them simultaneously. But this is more of a
theoretical issue -- in practice that's not going to happen, and we
should change mypy's rules not to reject overloads on this basis
alone.)
|
Actually mypy normally doesn't reject overloads based on potential overlapping that could be introduced via multiple inheritance. I think that the operator method checks might still be picky about this, though. |
This commit is intended to resolve python#1270. Currently, running mypy on the following program: from typing import overload class Parent: @overload def foo(self, x: A) -> A: ... @overload def foo(self, x: B) -> B: ... class Child(Parent): @overload def foo(self, x: B) -> B: ... @overload def foo(self, x: A) -> A: ... ...will make mypy report the following error -- it considers the fact that we've swapped the order of the two variants to be unsafe: test.pyi:10: error: Signature of "foo" incompatible with supertype "Parent" This error message can be confusing for some users who may not be aware that the order in which your overloads are defined can sometimes matter/is something mypy relies on. This commit modifies the error message to the following to try and make this more clear: test.pyi:10: error: Signature of "foo" incompatible with supertype "Parent" test.pyi:10: note: Overload variants must be defined in the same order as they are in "Parent"
This commit is intended to resolve #1270. Currently, running mypy on the following program: from typing import overload class Parent: @overload def foo(self, x: A) -> A: ... @overload def foo(self, x: B) -> B: ... class Child(Parent): @overload def foo(self, x: B) -> B: ... @overload def foo(self, x: A) -> A: ... ...will make mypy report the following error -- it considers the fact that we've swapped the order of the two variants to be unsafe: test.pyi:10: error: Signature of "foo" incompatible with supertype "Parent" This error message can be confusing for some users who may not be aware that the order in which your overloads are defined can sometimes matter/is something mypy relies on. This commit modifies the error message to the following to try and make this more clear: test.pyi:10: error: Signature of "foo" incompatible with supertype "Parent" test.pyi:10: note: Overload variants must be defined in the same order as they are in "Parent"
Unclear if this order-matters issue is the same as python/mypy#1270 or a separate bug, but with the lower-arity overloads first, the higher-arity overloads were ignored ("too many arguments" errors from MyPy).
Not sure if this is considered part of the same issue or not, but I just had a situation where order of overloads made the difference between type checks passing correctly and false Broken:from typing import Callable, TypeVar, ParamSpec, overload
P = ParamSpec('P')
R1 = TypeVar('R1')
@overload
def compose(f1: Callable[P, R1]) -> Callable[P, R1]:
...
R2 = TypeVar('R2')
@overload
def compose(f2: Callable[[R1], R2], f1: Callable[P, R1]) -> Callable[P, R2]:
...
R3 = TypeVar('R3')
@overload
def compose(f3: Callable[[R2], R3], f2: Callable[[R1], R2], f1: Callable[P, R1]) -> Callable[P, R3]:
...
R4 = TypeVar('R4')
@overload
def compose(f4: Callable[[R3], R4], f3: Callable[[R2], R3], f2: Callable[[R1], R2], f1: Callable[P, R1]) -> Callable[P, R4]:
... Fixed (by changing order)from typing import Callable, TypeVar, ParamSpec, overload
P = ParamSpec('P')
R1 = TypeVar('R1')
R2 = TypeVar('R2')
R3 = TypeVar('R3')
R4 = TypeVar('R4')
@overload
def compose(f4: Callable[[R3], R4], f3: Callable[[R2], R3], f2: Callable[[R1], R2], f1: Callable[P, R1]) -> Callable[P, R4]:
...
@overload
def compose(f3: Callable[[R2], R3], f2: Callable[[R1], R2], f1: Callable[P, R1]) -> Callable[P, R3]:
...
@overload
def compose(f2: Callable[[R1], R2], f1: Callable[P, R1]) -> Callable[P, R2]:
...
@overload
def compose(f1: Callable[P, R1]) -> Callable[P, R1]:
... |
We have made some changes to overload resolution since and it is expected that overload order matters. Any related problems should be discussed in a new issue, not in this ancient closed issue. |
Turns out the issue in my last comment wasn't even an ordering issue, it was an interleaving issue - eiher order works fine so long as all |
I am trying to model a generic container (a Pandas Series though it shouldn't matter too much for this). The container has a generic "value type" and a generic "index type". When iterating over the container, you get the value type back. So I tried with:
This gives me an error:
That baffled me for a while and on a whim, I tried reordering the two signatures:
The error is now gone! :-)
When I first got the error, I tried going into
typing.py
to see exactly what signature Sequence has. That didn't help me since Sequence is defined asI think it could have been helpful if mypy could have written the exact types it was comparing.
This was tested with 0ec0cb4.
The text was updated successfully, but these errors were encountered: