-
Notifications
You must be signed in to change notification settings - Fork 1
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
Notes on Type-Hinting compose
#16
Comments
In my stubs, I type-hinted arities up to 16. That seemed like a good spot for reliably feels-instant type-checking speed. I initially tried going all the way up to 256, but that was very slow, especially when there was a typing error, because modern type checkers seem to check every overload (they don't pre-separate/narrow by arity), so if there's a type mismatch and you have 256 overloads, all 256 get checked for a possible match before the type checker gives up. |
I also wrote a little script to generate compose overloads up to some arity, since it's obviously too much of a tedium to manually generate them. Here's a version of that simplified down to your needs: #!/usr/bin/env python3
def _callable(arguments, return_):
return f'Callable[{arguments}, {return_}]'
def _overload(name, arguments, return_):
return f'@overload\ndef {name}({arguments}) -> {return_}:\n ...'
def _overloads(name, up_to):
argument = _callable('P', 'R1')
arguments = f'f1: {argument}, /'
yield _overload(name, arguments, _callable('P', 'R1'))
for number in range(2, up_to):
argument = _callable(f'[R{number-1}]', f'R{number}')
arguments = f'f{number}: {argument}, {arguments}'
yield _overload(name, arguments, _callable('P', f'R{number}'))
print('from typing import Callable, ParamSpec, TypeVar, overload')
print("P = ParamSpec('P')")
for number in range(1, 16):
print(f"R{number} = TypeVar('R{number}')")
for overload in _overloads('compose', 16):
print(overload) If I remember right, |
Oh, my compose also raises an error instead of returning the identity function in the zero arguments case. I can't remember what funcy's does, but if it does the latter, you'll also want: @overload
def compose() -> Callable[[R1], R1]:
... |
Note that the overloads have to be right after each other. I had been tempted to interleave each additional |
Of course, the other complication we have here that I didn't have with my compose is funcy's "extended function semantics". I don't have a good answer to that, short of a combinatoric explosion of type hint overloads. And even that doesn't really work fully because the functions produced by |
I recently finally sat down and made
compose-stubs
for mycompose
, so here are some notes in case it helps here with the type hints for funcy's compose.Unfortunately, there's no Good way to do it. But it's possible to brute-force it with overloads up to some finite arity:
ParamSpec
is only available on 3.10 and up. Personally I didn't bother with compatibility to older Pythons in my stubs, but it would be easy enough to gracefully degrade fromParamSpec(P)
to f.e....
if you want to support older Pythons:The text was updated successfully, but these errors were encountered: