Removing `async` keyword form PEP 677
Pradeep, Guido and I are leaning toward removing the `async` part of PEP 677. There are several reasons: - If we leave `async` in, then `async (int) -> bool` and `(int) -> Awaitable[bool]` are the same - This violates that there should only be one obvious way to do things - It also might lead to a mismatch between written types and the errors returned by type checkers, leading to unnecessary confusion - It looks like < 5% of callable types return Awaitable anyway - It has explicitly been brought up in python-dev as unnecessary complexity, and we largely agree with this criticism. I wanted to float the idea of cutting `async` here first since so many folks from this thread contributed to the proposal in PEP 677. If there's no strong opposition, I'll probably remove it after the holidays. Cheers, - Steven
I'm fine with removing `async` from the spec. I think it's a reasonable simplification and eliminates some of the special-case parsing, as mentioned in the python-dev thread. That same thread also mentions the `**` syntax for ParamSpecs. I'm OK eliminating this too. As someone mentioned, it requires special-case parsing, is not needed for correct semantic analysis, and (IMO) adds relatively little in the way of readability. I'm also OK leaving it in if others feel strongly about it and it doesn't become an obstacle for PEP 677 ratification. -Eric
To be clear, you propose that we write (int, P) -> str instead of (int, **P) -> str, with the same semantics (triggered by P being a ParamSpec), right? On Wed, Dec 22, 2021 at 9:15 AM Eric Traut <eric@traut.com> wrote:
I'm fine with removing `async` from the spec. I think it's a reasonable simplification and eliminates some of the special-case parsing, as mentioned in the python-dev thread.
That same thread also mentions the `**` syntax for ParamSpecs. I'm OK eliminating this too. As someone mentioned, it requires special-case parsing, is not needed for correct semantic analysis, and (IMO) adds relatively little in the way of readability. I'm also OK leaving it in if others feel strongly about it and it doesn't become an obstacle for PEP 677 ratification.
-Eric _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: guido@python.org
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
If true, how would you write a callable where ParamSpec is an actual parameter? On Wed, 2021-12-22 at 10:08 -0800, Guido van Rossum wrote:
To be clear, you propose that we write (int, P) -> str instead of (int, **P) -> str, with the same semantics (triggered by P being a ParamSpec), right?
On Wed, Dec 22, 2021 at 9:15 AM Eric Traut <eric@traut.com> wrote:
I'm fine with removing `async` from the spec. I think it's a reasonable simplification and eliminates some of the special-case parsing, as mentioned in the python-dev thread.
That same thread also mentions the `**` syntax for ParamSpecs. I'm OK eliminating this too. As someone mentioned, it requires special- case parsing, is not needed for correct semantic analysis, and (IMO) adds relatively little in the way of readability. I'm also OK leaving it in if others feel strongly about it and it doesn't become an obstacle for PEP 677 ratification.
-Eric _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: guido@python.org
_______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: pbryan@anode.ca
On Wed, Dec 22, 2021 at 10:18 AM Paul Bryan <pbryan@anode.ca> wrote:
If true, how would you write a callable where ParamSpec is an actual parameter?
ParamSpec can not be used in any other way. It is not a type, it is a magic thing that has special semantics. You cannot have something like ``` P = ParamSpec("P") def foo(a: bool, p: P) -> str: ... ``` -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
@Paul, could you clarify what you mean? An example would be helpful. Do you want to pass a ParamSpec object as an argument to the callable, treating it like a runtime object rather than a special form? If so, then you'd annotate it as `(ParamSpec) -> None`. Is that what you mean? -Eric
I'd be okay with removing `**P` if we get that advice from many directions. But I'd much prefer to keep it: - **P is semantically very different from a normal variable, and the fact that it's a ParamSpec can live much higher up in the module. I think this can be a readability issue on unfamiliar code, even though it isn't on code that we're actively writing. - Given that we're introducing a similar *-for-unpack syntax in PEP 646, it seems inconsistent to me not to use a special syntax for ParamSpec So I'm not inclined to remove it just based on that one thread.
As a big user of async frameworks I'd really like to try and keep this as its much more succinct than having to import Awaitable from collections.abc and as builtin syntax for type annotations is where Python seems to be headed I think removing this would be annoying especially down the line.
I had assumed ParamSpec was a type; Guido has corrected me on that. On Wed, 2021-12-22 at 18:24 +0000, Eric Traut wrote:
@Paul, could you clarify what you mean? An example would be helpful.
Do you want to pass a ParamSpec object as an argument to the callable, treating it like a runtime object rather than a special form? If so, then you'd annotate it as `(ParamSpec) -> None`. Is that what you mean?
-Eric _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: pbryan@anode.ca
On Wed, Dec 22, 2021 at 7:13 AM Steven Troxler <steven.troxler@gmail.com> wrote:
Pradeep, Guido and I are leaning toward removing the `async` part of PEP 677.
There are several reasons: - If we leave `async` in, then `async (int) -> bool` and `(int) -> Awaitable[bool]` are the same - This violates that there should only be one obvious way to do things - It also might lead to a mismatch between written types and the errors returned by type checkers, leading to unnecessary confusion - It looks like < 5% of callable types return Awaitable anyway - It has explicitly been brought up in python-dev as unnecessary complexity, and we largely agree with this criticism.
For sync programs, it doesn't matter what we do, because they'll never write `async` or `Awaitable`. For async programs, having to put `Awaitable` everywhere adds a lot of visual noise. Most Python programs are sync, so any async-related syntax is necessarily going to be rare in absolute terms, but that's not really the relevant audience to think about. For modern code, `Awaitable` isn't used at definition point: you just write `async def foo(a: int) -> bool`. So keeping it in PEP 677 would make definition syntax and callable type syntax more consistent. I think it's a big win for usability. I also don't think it violates "one obvious way" -- emphasis on "obvious" :-). With PEP 677 as currently written, using `async` everywhere is the "obvious" way; `Awaitable` becomes a detail that only type nerds have to think about. -n -- Nathaniel J. Smith -- https://vorpus.org
On Wed, Dec 22, 2021 at 3:24 PM Nathaniel Smith <njs@pobox.com> wrote:
On Wed, Dec 22, 2021 at 7:13 AM Steven Troxler <steven.troxler@gmail.com> wrote:
Pradeep, Guido and I are leaning toward removing the `async` part of PEP
677.
There are several reasons: - If we leave `async` in, then `async (int) -> bool` and `(int) ->
Awaitable[bool]` are the same
- This violates that there should only be one obvious way to do things - It also might lead to a mismatch between written types and the errors returned by type checkers, leading to unnecessary confusion - It looks like < 5% of callable types return Awaitable anyway - It has explicitly been brought up in python-dev as unnecessary complexity, and we largely agree with this criticism.
For sync programs, it doesn't matter what we do, because they'll never write `async` or `Awaitable`. For async programs, having to put `Awaitable` everywhere adds a lot of visual noise. Most Python programs are sync, so any async-related syntax is necessarily going to be rare in absolute terms, but that's not really the relevant audience to think about.
For modern code, `Awaitable` isn't used at definition point: you just write `async def foo(a: int) -> bool`. So keeping it in PEP 677 would make definition syntax and callable type syntax more consistent. I think it's a big win for usability.
I also don't think it violates "one obvious way" -- emphasis on "obvious" :-). With PEP 677 as currently written, using `async` everywhere is the "obvious" way; `Awaitable` becomes a detail that only type nerds have to think about.
While I agree with the overall philosophy here, the async keyword in annotation context is a syntax addition that could be deferred until after PEP 677 to appear in a later version. As a side note, Awaitable is available from the typing module where typing users are already importing a pile from, as well as collections.abc. But they appear to be different things. Eek. `typing.Awaitable` vs `<class 'collections.abc.Awaitable'>`. -gps
-n
-- Nathaniel J. Smith -- https://vorpus.org _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: greg@krypto.org
On Wed, Dec 22, 2021 at 18:48 Gregory P. Smith <greg@krypto.org> wrote:
On Wed, Dec 22, 2021 at 3:24 PM Nathaniel Smith <njs@pobox.com> wrote:
On Wed, Dec 22, 2021 at 7:13 AM Steven Troxler <steven.troxler@gmail.com> wrote:
Pradeep, Guido and I are leaning toward removing the `async` part of
PEP 677.
There are several reasons: - If we leave `async` in, then `async (int) -> bool` and `(int) ->
- This violates that there should only be one obvious way to do
Awaitable[bool]` are the same things
- It also might lead to a mismatch between written types and the errors returned by type checkers, leading to unnecessary confusion - It looks like < 5% of callable types return Awaitable anyway - It has explicitly been brought up in python-dev as unnecessary complexity, and we largely agree with this criticism.
For sync programs, it doesn't matter what we do, because they'll never write `async` or `Awaitable`. For async programs, having to put `Awaitable` everywhere adds a lot of visual noise. Most Python programs are sync, so any async-related syntax is necessarily going to be rare in absolute terms, but that's not really the relevant audience to think about.
For modern code, `Awaitable` isn't used at definition point: you just write `async def foo(a: int) -> bool`. So keeping it in PEP 677 would make definition syntax and callable type syntax more consistent. I think it's a big win for usability.
I also don't think it violates "one obvious way" -- emphasis on "obvious" :-). With PEP 677 as currently written, using `async` everywhere is the "obvious" way; `Awaitable` becomes a detail that only type nerds have to think about.
While I agree with the overall philosophy here, the async keyword in annotation context is a syntax addition that could be deferred until after PEP 677 to appear in a later version.
As a side note, Awaitable is available from the typing module where typing users are already importing a pile from, as well as collections.abc. But they appear to be different things. Eek. `typing.Awaitable` vs `<class 'collections.abc.Awaitable'>`.
Really? They look closely related to me. What strikes you as different?
-gps
-n
-- Nathaniel J. Smith -- https://vorpus.org _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: greg@krypto.org
_______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: guido@python.org
-- --Guido (mobile)
As a side note, Awaitable is available from the typing module where typing
users are already importing a pile from, as well as collections.abc. But they appear to be different things. Eek. `typing.Awaitable` vs `<class 'collections.abc.Awaitable'>`.
Really? They look closely related to me. What strikes you as different?
I just did a quick repr check. They're clearly not a reference to the same thing. If I went and looked at the implementation I'm assuming they're ultimately the same thing for typing purposes? I just found it odd about the comment earlier about needing to import collections.abc for Awaitable. At first glance that doesn't appear necessary. -gps
(tl;dr: None of this is related to the thread's topic, and there's no need for alarm.) On Wed, Dec 22, 2021 at 9:06 PM Gregory P. Smith <greg@krypto.org> wrote:
As a side note, Awaitable is available from the typing module where typing
users are already importing a pile from, as well as collections.abc. But they appear to be different things. Eek. `typing.Awaitable` vs `<class 'collections.abc.Awaitable'>`.
Really? They look closely related to me. What strikes you as different?
I just did a quick repr check. They're clearly not a reference to the same thing.
If I went and looked at the implementation I'm assuming they're ultimately the same thing for typing purposes? I just found it odd about the comment earlier about needing to import collections.abc for Awaitable. At first glance that doesn't appear necessary.
For historical reasons all things in typing that correspond to things in collections.abc (Mapping, Iterable, etc.) are all slightly different than the thing they try to resemble -- the versions in collections.abc were traditionally not generic (i.e. couldn't be subscripted), PEP 585 changed that (it has a full list of things affected) but for backwards compatibility they're not 100% equivalent at runtime. (Also, note the irregularity for [Abstract]Set in PEP 585.) Once you no longer need backwards compatibility with Python < 3.9, you *should* replace typing.XXX with collections.abc.XXX though, and fix whatever issues crop up -- I wouldn't know what would, but things that depend on typing internals might be affected. This is one reason we need to wait a long time before even deprecating these things. -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
As much as i can see the benefits of removing the `async` keyword from PEP 677, i would very much prefer it to stay, It makes the syntax a lot cleaner when it comes to async code, returning `Awaitable[...]` is a lot more hassle than prepending `async` to the start of the signature.
participants (8)
-
Angelo Kontaxis
-
Eric Traut
-
Gregory P. Smith
-
Guido van Rossum
-
James H-B
-
Nathaniel Smith
-
Paul Bryan
-
Steven Troxler