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/

Reply via email to