I've been thinking about readability hard because I share many of your concerns
about readability.
I'm starting to think parenthesizing the outside might work much better in
practice:
```
(int, str -> bool)
```
instead of
```
(int, str) -> bool
```
This looks a bit less familiar, but it
- eliminates any situation
- helps the eye group together functions (and lets us use an editor's
go-to-delimiter if we get lost!)
An example
=========
The function
----------------
To get at what I mean, here's a nice simple function:
```
def zip(f, g):
def zipped(x: int, y: str):
return f(x), g(y)
return zipped
```
typing.Callable
--------------------
Here's it's type using typing.Callable:
```
typing.Callable[
[typing.Callable[[int], bool], typing.Callable[[str], float]],
typing.Callable[[int, str], tuple[bool, float]
]
```
which seems ugly. It's actually not bad compared to a lot of production code,
but this is the kind of thing that led to PEP 677.
current PEP 677 proposal
----------------------------------
With the current PEP 677 proposal, writing the type on one line we get
```
((int) -> float, (str) -> bool) -> (int, str) -> tuple[float, bool]
```
I prefer this to the Callable version. But it’s dense, and I do agree it
illustrates some readability issues with PEP 677.
Using (int, str -> bool) syntax
--------------------------------
Here’s the type if we change the syntax to put the right parenthesis after the
return type:
```
((int -> float), (str -> bool) -> (int, str -> tuple[float, bool])
```
To my eyes, most of the pain points are now eliminated.
- there’s never a double-arrow due to callable in return position
- even for argument types, to my eyes it’s now easier to read
An added bonus is we no longer have to think about double-arrows when a
callable type is in the return position of a function, e.g.:
```
def f() -> (int, str -> bool): ...
```
And it solves another major usability problem we found - writing optional
callables - because it’s now no problem at all to write
```
(int, str -> bool) | None
```
as the type of an optional callable argument.
New edge cases / readability issues?
-------------------------------------
I’m pretty sure *all* existing edge cases and readability issues are basically
solved by this syntax because the grouping becomes obvious.
The only new edge case I can see is that we might not like `(-> bool)` for
parameterless callables. I’d be okay with that, but I’d also be down with a
hack like `(() -> bool)`.
I don’t actually think it matters much - by making this change we would trade
multiple edge cases in *complicated* examples for a single edge case in the
*simplest possible* example where readability isn’t a big problem.
_______________________________________________
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/AXRKGCPP2GTDRINQ6NQYM743Y6EH6FO5/
Code of Conduct: http://python.org/psf/codeofconduct/