> An await outside async def, would map to awaitable.run().

> A call to baz() would thus create a coroutine foo(), and then run() it.

-1. The `await` expression already has a well-defined purpose of suspending
the coroutine it's used within until the awaitable is completed. I think
this change in behavior would be rather confusing, and results in minimal
(if any) practical benefit since you can already accomplish the main
intended behavior of effectively running coroutines as blocking subroutines
(see next section).

> In particular, this could allow one to turn any arbitrary async coroutine
into a blocking subroutine, as long as it supports this run() protocol.
This would be great for refactoring existing blocking code into async -
just use stuff as if it's sync, then when you're done, switch up your
function with async def, and change relevant calls into it into "await"
calls. Rinse and repeat until you're ready to add a top-level event loop.

This can already be effectively accomplished by gradually converting the
synchronous code into coroutines and running them individually with
asyncio's loop.run_until_complete(coro()) (which blocks until finished)
from a subroutine while the other parts of the code are still transitioning
to async. However, the bulk of the effort is considering the architecture
of the program, specifically analyzing the parts that need to be completed
sequentially vs those that can be completed concurrently, and then figuring
out exactly when/where the results are needed. So, I don't think that
making an await expression outside of a coroutine function an alias to an
awaitable.run() and effectively doing the same thing as
loop.run_until_complete() would save substantial development time, and it
adds additional unneeded complexity to the await expression for little to
no practical benefit.

Also, I very much appreciate knowing that when I see "await" used, I'm
certain it's being called within a coroutine and more importantly, the
expected behavior. Having to check whether the function is awaited in is a
coroutine or a subroutine to determine the behavior could prove to be quite
cumbersome in non-trivial programs. A significant part of why await was
added in the first place was to avoid the ambiguity present with "yield
from". In general, I think there's a significant advantage in having a
singular purpose for a keyword, rather than changing based on where it's
used.

> Optionally, this would also allow us to deprecate blocking APIs (like
open(), etc

Huge -1 for deprecating the existing blocking APIs. Although converting
some IO-bound functions to asynchronous equivalents can yield significant
performance benefits (when structured optimally), it's not always
worthwhile to do so. Particularly in situations where the underlying OS
call doesn't have asynchronous support (frequently the case for async file
system operations), or when the intended use case for the program wouldn't
benefit from the performance improvements enough to justify the added
complexity and development time. So blocking IO-bound functions still have
a significant purpose, and should definitely __not__ be deprecated. Even if
there was a working automatic conversion process to place an "await" before
each of the calls, it would still cause a lot of breakage and add
additional noise to the code that wouldn't provide additional useful
context.

Also, consider the amount of times that various Python tutorials and
textbooks use open() that would all have to be rewritten because it no
longer works without "await" before it. Realistically speaking, I don't
think there's any chance of something as commonly used as open() being
deprecated, regardless how far out the removal would be. Even if/when async
file system support at the OS level becomes the mainstream (which it
currently isn't), I still don't think it would be worth breaking open().

> and asyncio, and merge them into one TBD API. Perhaps as part of Python 4.

Even if I agreed with the main proposal, I would still be against this
part. Stdlib module deprecation is a very long process that has to be
strongly justified, considering the amount of breakage that would occur
from its eventual removal. So even with the assumption that the proposal
would provide some real benefit in the transition from sync to async (which
I disagree with), I don't think this would come even close to justifying a
full deprecation of asyncio into a separate "TBD API".

Thanks for sharing the idea Soni, but I would personally be opposed to
every component of the proposal.

On Fri, Jun 12, 2020 at 7:20 PM Soni L. <fakedme...@gmail.com> wrote:

>
>
> On 2020-06-12 5:47 p.m., J. Pic wrote:
>
> Hi all,
>
> Currently, you can not use await outside an async function, the following
> code:
>
>   async def lol():
>     return 'bar'
>
>   def test():
>     return await lol()
>
>   print(test())
>
> Will fail with: SyntaxError: 'await' outside async function
>
> Of course, you can use asyncio.run and then it works fine:
>
>   import asyncio
>
>   async def lol():
>     return 'bar'
>
>   def test():
>     return asyncio.run(lol())
>
>   print(test())
>
> Why not make using await do asyncio.run "behind the scenes" when called
> outside async function ?
>
> Thank you in advance for your replies
>
>
> What if we extend awaitables to be optionally "runnable"?
>
> An await outside async def, would map to awaitable.run(). In the specific
> case of coroutines, this would also automatically propagate down. E.g.
>
> async def foo():
>   await bar()
>
> def baz()
>   await foo()
>
> A call to baz() would thus create a coroutine foo(), and then run() it. By
> my proposed semantics, the await bar() would also call run() on the result
> of bar()!
>
> In particular, this could allow one to turn any arbitrary async coroutine
> into a blocking subroutine, as long as it supports this run() protocol.
> This would be great for refactoring existing blocking code into async -
> just use stuff as if it's sync, then when you're done, switch up your
> function with async def, and change relevant calls into it into "await"
> calls. Rinse and repeat until you're ready to add a top-level event loop.
>
> Optionally, this would also allow us to deprecate blocking APIs (like
> open(), etc) and asyncio, and merge them into one TBD API. Perhaps as part
> of Python 4. (e.g. turn existing open() into await open(), particularly in
> non-async-def. I *think* this could be done automatically as part of some
> sort of "3to4", even.)
>
>
> --
> ∞
>
> _______________________________________________
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to 
> python-ideas-leave@python.orghttps://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at 
> https://mail.python.org/archives/list/python-ideas@python.org/message/LOCYSYVRKXI45QQJOLYGZV6H2CBYTB7F/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
>
> _______________________________________________
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/Y73VH53OXZZ2GDWRVGRX2B76U3TSHYZF/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/NSHWPSW6PBQEPBNVGRHQW6B2AHOE6A2M/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to