
On Thu, Dec 23, 2021 at 5:13 PM Guido van Rossum <guido@python.org> wrote:
On Thu, Dec 23, 2021 at 3:24 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Thu, Dec 23, 2021 at 02:09:50PM -0800, Guido van Rossum wrote:
Without decorator too (that was Lukasz’ idea). Why bother with the decorator (*if* we were to go there)?
So that
def func(params): pass
creates a function object, and
def func(params)
makes a Callable type object?
No, no, no. That syntax has already been discredited.
Mark's proposal was ``` @Callable def func(params): pass ``` My question is, why does it need `@Callable`?
My guess is the thinking is to prevent anyone from thinking that the function is actually meant to do anything other than be a type signature for a callable. Otherwise it's very much convention to know what is purposefully a no-op/always-returns-None function meant to be a callable type based either on the naming scheme or some other practice like the ellipsis body versus you just haven't implemented the function yet.
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)) ```
It probably is more useful without the decorator. For instance, if you want to type a function parameter to something that acts like `open()`, then would you want to reproduce that type annotation or just say `opener: builtins.open`? This would actually lean into duck typing even by allowing people to easily say, "I want _something_ that directly quacks like this callable" instead of having to manually duplicate the API with a separate type annotation (which one could still do if they were worried about code drift in regards to expectations). Basically it makes all functions and methods immediately a potential type annotation which could be rather powerful and could lead to more callables being used compared to single-method protocols if there isn't some OOP need to pass an object with a method around.