@Kevin correct, that's the point I'd like to discuss. Most other mainstream languages that implements async/await expose the programming model with Tasks/Futures/Promises as opposed to coroutines PEP 492 states 'Objects with __await__ method are called Future-like objects in the rest of this PEP.' but their behavior differs from that of Futures in this core way. Given that most other languages have standardized around async returning a Future as opposed to a coroutine I think it's worth exploring why Python differs.
There's a lot of benefits to making the programming model coroutines without a doubt. It's absolutely brilliant that I can just call code annotated with @asyncio.coroutine and have it just work. Code using the old @asyncio.coroutine/yield from syntax should absolutely stay the same. Similarly, since ES7 async/await is backed by Promises it'll just work for any existing code out there using Promises. My proposal would be to automatically wrap the return value from an `async` function or any object implementing `__await__` in a future with `asyncio.ensure_future()`. This would allow async/await code to behave in a similar manner to other languages implementing async/await and would remain compatible with existing code using asyncio. What's your thoughts? Thanks, Roy On Tue, Dec 15, 2015 at 3:35 PM, Kevin Conway <kevinjacobcon...@gmail.com> wrote: > I think there may be somewhat of a language barrier here. OP appears to be > mixing the terms of coroutines and futures. The behavior OP describes is > that of promised or async tasks in other languages. > > Consider a JS promise that has been resolved: > > promise.then(function (value) {...}); > > promise.then(function (value) {...}); > > Both of the above will execute the callback function with the resolved > value regardless of how much earlier the promise was resolved. This is not > entirely different from how Futures work in Python when using > 'add_done_callback'. > > The code example from OP, however, is showing the behaviour of awaiting a > coroutine twice rather than awaiting a Future twice. Both objects are > awaitable but both exhibit different behaviour when awaited multiple times. > > A scenario I believe deserves a test is what happens in the asyncio > coroutine scheduler when a promise is awaited multiple times. The current > __await__ behaviour is to return self only when not done and then to return > the value after resolution for each subsequent await. The Task, however, > requires that it must be a Future emitted from the coroutine and not a > primitive value. Awaiting a resolved future should result > > On Tue, Dec 15, 2015, 14:44 Guido van Rossum <gu...@python.org> wrote: > >> Agreed. (But let's hear from the OP first.) >> >> On Tue, Dec 15, 2015 at 12:27 PM, Andrew Svetlov < >> andrew.svet...@gmail.com> wrote: >> >>> Both Yury's suggestions sounds reasonable. >>> >>> On Tue, Dec 15, 2015 at 10:24 PM, Yury Selivanov >>> <yselivanov...@gmail.com> wrote: >>> > Hi Roy and Guido, >>> > >>> > On 2015-12-15 3:08 PM, Guido van Rossum wrote: >>> > [..] >>> >> >>> >> >>> >> I don't know how long you have been using async/await, but I wonder if >>> >> it's possible that you just haven't gotten used to the typical usage >>> >> patterns? In particular, your claim "anything that takes an >>> `awaitable` has >>> >> to know that it wasn't already awaited" makes me sound that you're >>> just >>> >> using it in an atypical way (perhaps because your model is based on >>> other >>> >> languages). In typical asyncio code, one does not usually take an >>> awaitable, >>> >> wait for it, and then return it -- one either awaits it and then >>> extracts >>> >> the result, or one returns it without awaiting it. >>> > >>> > >>> > I agree. Holding a return value just so that coroutine can return it >>> again >>> > seems wrong to me. >>> > >>> > However, since coroutines are now a separate type (although they share >>> a lot >>> > of code with generators internally), maybe we can change them to throw >>> an >>> > error when they are awaited on more than one time? >>> > >>> > That should be better than letting them return `None`: >>> > >>> > coro = coroutine() >>> > await coro >>> > await coro # <- will raise RuntimeError >>> > >>> > >>> > I'd also add a check that the coroutine isn't being awaited by more >>> than one >>> > coroutine simultaneously (another, completely different issue, more on >>> which >>> > here: https://github.com/python/asyncio/issues/288). This was fixed >>> in >>> > asyncio in debug mode, but ideally, we should fix this in the >>> interpreter >>> > core. >>> > >>> > Yury >>> > _______________________________________________ >>> > Python-Dev mailing list >>> > Python-Dev@python.org >>> > https://mail.python.org/mailman/listinfo/python-dev >>> > Unsubscribe: >>> > >>> https://mail.python.org/mailman/options/python-dev/andrew.svetlov%40gmail.com >>> >>> >>> >>> -- >>> Thanks, >>> Andrew Svetlov >>> >> _______________________________________________ >>> Python-Dev mailing list >>> Python-Dev@python.org >>> https://mail.python.org/mailman/listinfo/python-dev >>> >> Unsubscribe: >>> https://mail.python.org/mailman/options/python-dev/guido%40python.org >>> >> >> >> >> -- >> --Guido van Rossum (python.org/~guido) >> _______________________________________________ >> Python-Dev mailing list >> Python-Dev@python.org >> https://mail.python.org/mailman/listinfo/python-dev >> Unsubscribe: >> https://mail.python.org/mailman/options/python-dev/kevinjacobconway%40gmail.com >> > > _______________________________________________ > Python-Dev mailing list > Python-Dev@python.org > https://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: > https://mail.python.org/mailman/options/python-dev/rwilliams%40lyft.com > >
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com