Skip to content

Conversation

@stroxler
Copy link
Contributor

Almost nothing material to the proposal itself is changing, the only specification tweak is that we updated the grammar snippet for supporting PEP 646 to include a guard against '...'.

All other edits are just for readability:

  • fixes for typos and markup issues
  • clarifying examples and/or wording
  • moving subsections between sections (mainly shrinking "Motivation" and expanding "Rationale")

This closes all open suggestions from review of the initial PR except that:

  • I still have a ParamSpec example in Rationale, which may be worth removing
  • There's a suggestion to add a Statistics subsection to the Resources section and I haven't gotten to that yet

Going with Pradeep's suggested order:
- untyped example
- correct types
- partially-typed code
- our proposal
Copy link
Contributor

@pradeep90 pradeep90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High-level: Wording changes look good. Can do a more detailed review later on.

However, I have some major readability concerns about -> in callable types being ambiguous with the -> from the function signature. See comment below.

work as a drop-in replacement.


Motivation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High-level: Motivation is much clearer to read!


With our proposal, the example looks like this::

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

@pradeep90 pradeep90 Dec 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gvanrossum @stroxler Wow, I'm having serious second thoughts about the readability of (int) -> str given that Python's def signatures also use ->. I had to read the above signature multiple times to follow it.

TypeScript, etc. don't have this problem because their function signatures don't use an arrow for the return type; they use a colon ::

function flat_map(xs: number[], f: (x: number) => number[]): number[] { }

I think our example is actually a bit more readable with =>:

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

We no longer have to mentally disambiguate the arrow for the callable and the arrow for the def.

For completeness, here are all the other examples from this PEP:

With a dash arrow:

def with_retries(f: (**P) -> R) -> (bool, **P) -> R: ...

def customize_response(
        response: Response,
        customizer: async (Response, list[UserSetting]) -> Response,
) -> Response: ...

# the above example as a one-liner:
def foo(resp: Response, func: async (Response, list[Setting]) -> Response) -> Response: ...

def f() -> (int, str) -> bool: pass

def f() -> (int) -> (str) -> bool: pass

def f() -> async (int) -> async (str) -> bool: pass

With an equals arrow:

def with_retries(f: (**P) => R) -> (bool, **P) => R: ...

def customize_response(
        response: Response,
        customizer: async (Response, list[UserSetting]) => Response,
) -> Response: ...

# the above example as a one-liner:
def foo(resp: Response, func: async (Response, list[Setting]) => Response) -> Response: ...

def f() -> (int, str) => bool: pass

def f() -> (int) => (str) => bool: pass

def f() -> async (int) => async (str) => bool: pass

What do you think? This might remove a lot of the ambiguity when reading or writing callback types. The downside is that it doesn't exactly resemble function arrows, which might be fine, since it doesn't have named parameters either.

If this seems reasonable, we could open it up for discussion (or do that in parallel with python-dev review).

Another option is to rewrite a few typeshed files with both styles to let people get a feel for it in real-world code. Until now, we were just going off the principle that "it should look like function signatures", which it turns out can actually hurt readability.

@gvanrossum
Copy link
Member

@pradeep90, your comment about readability of -> should go to the python-dev discussion, not here.

@pradeep90
Copy link
Contributor

@gvanrossum Bikeshedding can get messy and heated (as we have seen on this PEP 😄 ). It seems risky to do it for the first time on python-dev. I didn't want our main question about Python syntax changes to be derailed by bikeshedding over the arrow token. I thought it might be better to reach consensus on typing-sig and iron out any concerns before opening it up on python-dev.

But we can raise it on python-dev if you feel strongly.

@stroxler
Copy link
Contributor Author

stroxler commented Dec 15, 2021

I'm not opposed to changing to =>, and I do think typing-sig is probably a less-noisy forum to initially raise it.

My personal on this is that

  • if there's one line per function argument, the -> seems easy to read
  • without syntax highlighting, it's definitely not easy to read long one-line signatures
    • I'm not sure how much syntax highlighting might help
  • => is likely better for readability but bad for coherence/consistency. It's unclear how to trade those off
    • Proposing => also does impact potential arrow-based lambda syntax. That particular concern
      will presumably be more salient to python-dev than typing-sig

@stroxler stroxler marked this pull request as ready for review December 15, 2021 00:06
@stroxler stroxler requested a review from gvanrossum as a code owner December 15, 2021 00:06
@stroxler
Copy link
Contributor Author

It seems like we'll stick with -> for now. I think it makes sense to merge this round of updates so we can move the discussion to python-dev

@gvanrossum gvanrossum merged commit c8a66e3 into python:main Dec 16, 2021
@stroxler stroxler deleted the callable-type-syntax-v2 branch December 16, 2021 16:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants