On Thu, Dec 23, 2021 at 7:38 PM Barry Warsaw <ba...@python.org> wrote: > > On Dec 23, 2021, at 17:09, Guido van Rossum <gu...@python.org> wrote: > > > > Mark's proposal was > > ``` > > @Callable > > def func(params): pass > > ``` > > My question is, why does it need `@Callable`? Lukasz proposed just using > > any (undecorated) function, with the convention being that the body is > > `...` (to which I would add the convention that the function *name* be > > capitalized, since it is a type). My question (for Mark, or for anyone who > > supports `@Callable`) is why bother with the decorator. It should be easy > > to teach a type checker about this: > > > > ``` > > def SomeFn(x: float) -> int: > > ... > > > > def twice(f: SomeFn) -> SomeFn: > > return lambda x: f(f(x)) > > ``` > > That seems pretty intuitive to me. The conventions you mention would be just > that though, right? I.e. `pass` could be used, but whatever the body is it > would be ignored for type checking `twice()` in this case, right?
I think this was briefly mentioned in another thread, but it seems to have been lost in the discussion here, so I want to mention it again because I think it's important: aside from the verbosity and hassle of needing to always define callable types out-of-line and give them a name, another significant downside to the function-as-type approach is that generally Python signatures are too specific for intuitive use as a callback type. Note that in the example immediately above, a typechecker should error on this call: ``` def float_to_int(y: float) -> int: return int(y) twice(float_to_int) ``` The intent of the programmer was probably that `twice` should accept any function taking a single float argument and returning an int, but in fact, given the possibility of keyword calls, the names of non-positional-only parameters are part of the function signature too. Since the body of `twice` could call `f(x=...)`, a typechecker must error on the use of `float_to_int` as the callback, since its parameter is not named `x`. In order to correctly express their intent, the programmer must instead ensure that their callable type takes a positional-only argument: ``` def SomeFn(_x: float, /) -> int: ... ``` The need to almost always use the extra `/` in the callable type signature in order to get the desired breadth of signature, and the likelihood of forgetting it the first time around until someone tries to pass a second callback value and gets a spurious error, is in my mind a major negative to functions-as-callable-type. So I agree with Steven: this issue, plus the verbosity and out-of-line-ness, mean that Callable would continue to be preferable for many cases, meaning we'd end up with two ways to do it, neither clearly preferable to the other. I don't think out-of-line function-as-type could ever be an acceptable full replacement for Callable, whereas I think PEP 677 immediately would be. Carl _______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-le...@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/4QPK23NPIZ6GNV47J27S3ZPSM52LE3PD/ Code of Conduct: http://python.org/psf/codeofconduct/