On 2 Jun 2020, at 04:38, Mark Mendoza <mendoza.mark.a@gmail.com> wrote:
I recently discovered that MyPy supports a generic callable type shorthand that Pyre does not, namely things of the form
``` from typing import Callable, TypeVar T = TypeVar("T") def produce_no_op_decorator() -> Callable[[T], T]:... ```
MyPy interprets this as being of type `Callable[[], Callable<T>[[T], T]]` (mod https://github.com/python/mypy/issues/3924), while Pyre interprets it as being of type `Callable<T>[[], Callable[[T], T]]`, which we reject as being invalid.
Pyre interprets all free type variables in a def or class as being in the scope of that define/class. MyPy also does this in most circumstances with Callable[[T], T], as both checkers have identical interpretations of
``` T = TypeVar("T") def f(x: T) -> Callable[[T], T]: ... # def <T> (T) -> Callable[[T], T] # and def f(f: Callable[[T], T]) -> T: ... # def <T> (Callable[[T], T]) -> T #and def i() -> Tuple[Callable[[T], T], T]: ... # def <T> () -> Tuple[Callable[[T], T], T]: ... # and class Child(Base[Callable[[T], T]]): ... # class <T> Child(Base[Callable[[T], T]]) ```
Pyre and MyPy only differ here in that MyPy introduces a unique special case that alters the behavior for free variables: * inside a Callable type * in the return type of a def * not present in any parameter of the def * not present anywhere else in the return type that isn't also inside of a Callable type.
I can definitely see how this special case is helpful in making definitions for decorator factories more compact, but for us the inconsistency of this behavior from a user's perspective outweighs the concision.
With all that being said, given that the semantics of this are unspecified in any PEPs, I think it's fine for there to be a divergence in interpretation here. However, there are instances of this pattern in typeshed, which have been leading to strange behavior in Pyre.
Luckily, both MyPy and Pyre have a spelling of `produce_no_op_decorator` that they both agree on, and is mostly codified by a PEP:
``` from typing import Callable, TypeVar, Protocol T = TypeVar("T") class IdentityFunction(Protocol): def __call__(self, __x: T) -> T: ... def produce_no_op_decorator() -> IdentityFunction... ```
What are people's thoughts on modifying typeshed (like in https://github.com/python/typeshed/pull/4045) to change these instances to the commonly accepted spelling? _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: jakub@stasiak.at
For what it’s worth I, as a user, would really expect def f() -> Callable[[T], T] # and similar to be non-generic function returning a generic one (consistent with Mypy) and I’ve been using this pattern in my code for a long time now. But then I’d also expect def g() -> T to be rejected (how can the caller of the function influence T when there’s no parameter(s) of type T and it’s a free function as opposed to a method belonging to a class generic in T?). Mypy currently allows it but I don’t really see how it’s useful (I may not be seeing bigger picture): % cat test.py from typing import cast, TypeVar T = TypeVar('T') def foo() -> T: return cast(T, 'surprise') reveal_type(foo) reveal_type(foo()) % mypy test.py test.py:9: note: Revealed type is 'def [T] () -> T`-1' test.py:10: note: Revealed type is '<nothing>' What does Pyre do in this case? Best, Jakub