Steven D'Aprano wrote:uble the size of Callable.
> > I think it takes only the characters needed to write the name IntToIntFunc.
> ... you may only use it once.

Could you provide an example where it is only used once?

The only way I can imagine is that you use it here when when defining your 
complicated function that takes a callback (once), but then you never actually 
call that complicated function, even from test code, nor do you expect your 
users to do so.

> The status quo is that we can use an anonymous type in the annotation 
> without pre-defining it, using Callable.

OK.  I'm not sure it would be a good idea, but we agree it is legal.

> PEP 677 proposes a new, more compact syntax for the same. 

Does it?  I agree that "(int, float) -> bool" is more compact than 
typing.Callable[...], but that feels like optimizing for the wrong thing.

I dislike the PEP's flat_map as an example, because it is the sort of 
infrastructure function that carries no semantic meaning, but ... I'll use it 
anyhow.

    def flat_map(l, func):
        out = []
        for element in l:
            out.extend(f(element))
        return out


    def wrap(x: int) -> list[int]:
        return [x]

    def add(x: int, y: int) -> int:
        return x + y

It is reasonable to add a docstring to flat_map, but I grant that this doesn't 
work as well with tooling that might involve not actually seeing the function.

I agree that adding a long prefix of:

    from typing import Callable

    def flat_map(
        l: list[int],
        func: Callable[[int], list[int]]
    ) -> list[int]:

is undesirable.  But the biggest problem is not that "Callable..." has too many 
characters; the problem is that "Callable[[...], list[...]]" requires too many 
levels of sub-parsing. 

The PEP doesn't actually say what it proposes, [and you've suggested that my 
earlier attempt was slightly off, which may not bode well for likelihood of 
typos], but I'll *guess* that you prefer:

    def flat_map(
        l: list[int],
        func: ((int) ->[int])
    ) -> list[int]:

which is slightly shorter physically, but not much simpler mentally.  It 
therefore creates an attractive nuisance.

    def flat_map(
        l: list[int],
        func: wrap
    ) -> list[int]:

on the other hand, lets you read this definition without having to figure out 
what "wrap" does at the same time.  

"wrap" is a particularly bad example (because of the lack of semantic content 
in this example), but I think it still easily beats the proposed new solution, 
simply because it creates a "you don't need need to peer below this right now" 
barrier.


> Any proposal for function prototypes using 
> `def` is directly competing against Callable or arrow syntax for the 
> common case that we want an anonymous, unnamed type written in place.

I'm saying that catering to that "common" case is a trap, often leading you to 
a local optima that is bad globally.

> But if we can use an existing function as the prototype instead of 
> having to declare the prototype, that shifts the balance. 

I agree that re-using an existing function with the correct signature is 
better, *even* when that function doesn't make a good default.

...
> > I would say the opposite: most callback or key functions have very 
> simple signatures.
> If my function takes a key function, let's say:
> def spam(mylist:[str], 
>              a: int, 
>              b: float,
>              c: bool|None,
>              key: Callable[[str], str],
>              ) -> Eggs:
>         mylist = sorted(mylist, key=key)
>         ...
> the relevant signature is (str) -> str. Do we really need to give that a 
> predefined named prototype?
> def StrToStr(s: str) -> str: pass

If you really care about enforcing the str, then yes, it is worth saying

    key: str_key

and defining str_key function as an example

    def str_key(data:str)->str
        return str(data)

> I would argue that very few people would bother. 

Because it would usually be silly to care that the list really contained 
strings, as opposed to "something sortable".  So if you do care, it is worth 
making your requirement stand out, instead of losing it in a pile of what looks 
like boilerplate.

-jJ
_______________________________________________
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/32QYLA7UFTC54UM3CO3REIH57WLLBL6H/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to