-
Notifications
You must be signed in to change notification settings - Fork 268
Description
When you declare a function, your signature annotation serves three purposes.
- It allows a program to typecheck the body of the function, finding human errors
- It allows a program to typecheck the call sites of the function, finding more human errors
- It allows a human to quickly understand the usage of the function, preventing human errors.
Please excuse my poorly-motivated example below.
from typing import TypeVar, Callable, Dict, Any
T = TypeVar('T')
def reprify(f: Callable[[T], Any]) -> Callable[[T], str]:
def res(__x: T) -> str:
return repr(f(__x))
return res
@reprify
def nonsense(i: int) -> Dict[str, int]:
return {"nonsense": i}
s = nonsense(3)
reveal_type(s) # E: Revealed type is 'builtins.str'
The first two purposes are served. The computer can typecheck the body of the function, understanding that it is to return a dictionary inside. The computer can also typecheck the call site of the function, understanding that the decorator causes the function to return a string.
The last purpose is not served. To understand how to use the nonsense
function, a human must look at the signature of nonsense
, then remember to look at the signature of reprify
, and then perform a type calculation in their head combining the two.
I would like a way to optionally make a description of the type of nonsense
a call site sees, so the humans do not get confused. We can then tell a computer to check against the decorators.
One possibility, provided for its straw-person properties:
...
@reprify # type: (int) -> str
def nonsense(i: int) -> Dict[str, int]:
return {"nonsense": i}
...