Me and my big mouth… ![]()
Let me go over the SC’s arguments at the time, summarizing each cryptically:
- “Be cautious with new syntax.” While this looks like a fairly weak argument, it feels like an implicit criticism of the specific syntax chosen. I’ve now spent the past 8 months reading and writing copious amounts of TypeScript, and I have to agree that the TS syntax often feels cryptic, especially since there’s no distinctive token at the start. You can be quite far into a parenthesized list of things before you realize that it’s a lambda or callable type (they both use the
=>arrow in TS – which is easier because the TS parser always knows whether it’s parsing a type or an expression). - “Callable does work.” This was an easy argument to make because PEP 677 carefully chose not to offer features that re beyond Callable’s capabilities (such as optional args or keyword args). So maybe we should actually propose to support optional and keyword args from day one of the new proposal.
- “PEP 677 locks us into a syntax choice.” This is a weird one. Of course new syntax locks you in. But what potential future alternative use of
(a, b) -> xwere they thinking of? Most likely lambdas, but I think TypeScript suggests that we could reuse the same syntax if we wanted to. - Uneasy with multiple
->tokens. This would be easily addressed by changing the syntax to require that a callable to the right of->must be parenthesized. (It’s easy to drop that requirement in the future if we end up feeling too constrained by it.)
And their recommendation:
- “Prefer low complexity syntax, not requiring PEG to parse.” A repeat of (1) above, so they must feel rather strongly about the syntax. And it matches my intuition after using TypeScript.
Now what shall we make of this? I worry that proposing the same syntax (with or without additional features beyond Callable’s current capabilities) would set us up for another failure. (Pinging SC members on how they might feel is not very effective, they won’t commit until the new or revised PEP is properly reviewed on Discourse and then submitted for SC review.)
Would it be completely insane if Python went its own way here rather than trying to conform to what a few other languages do? My strawman: extend lambda to e.g. support the following syntax (here given by example):
lambda a, b: a * b # Old lambda syntax still works (NOT deprecated)
lambda(a: int, b: str) -> str: a * b # A typed lambda expression -- a function
lambda(int, str) -> str: ... # A type signature (maybe we can make `...` explicitly fail when called)
lambda(a: int, b: str) -> int: a * b # Can be used as a type signature or a lambda function
Note that the 3rd example lambda(int, str) -> str: ... might seem ambiguous – is that a lambda function with arguments named int and str, returning the value Ellipsis, or a type signature? We can either let this be decided by the presence of ..., or make this the way lambda with parenthesized arguments is always parsed. (A parameter would basically be [NAME ':'] EXPR rather than NAME [':' EXPR].)
If people think this is all terrible, let’s forget about it, but the lambda prefix makes at least human parsing a lot simpler (you know what you’re looking at from the first token you see).