On 25.06.2015 04:16, Steven D'Aprano wrote:
On Wed, Jun 24, 2015 at 11:21:54PM +0200, Sven R. Kunze wrote:
Thanks, Yury, for you quick response.

On 24.06.2015 22:16, Yury Selivanov wrote:
Sven, if we don't have 'async def', and instead say that "a function
is a *coroutine function* when it has at least one 'await'
expression", then when you refactor "useful()" by removing the "await"
>from it, it stops being a *coroutine function*, which means that it
won't return an *awaitable* anymore.  Hence the "await useful()" call
in the "important()" function will be broken.
I feared you would say that. Your reasoning assumes that *await* needs
an *explicitly declared awaitable*.

Let us assume for a moment, we had no async keyword. So, any awaitable
needs to have at least 1 await in it. Why can we not have awaitables
with 0 awaits in them?
I haven't been following the async discussion in detail, but I would
expect that the answer is for the same reason that you cannot have a
generator function with 0 yields in it.
Exactly. That is why I do not stop here.

'async def' guarantees that function always return a "coroutine"; it
eliminates the need of using @asyncio.coroutine decorator (or
similar), which besides making code easier to read, also improves the
performance.  Not to mention new 'async for' and 'async with' statements.
Recently, I read Guido's blog about the history of Python and how he
eliminated special cases from Python step by step. As I see it, the same
could be done here.

What is the difference of a function (no awaits) or an awaitable (> 1
awaits) from an end-user's perspective (i.e. the programmer)?
The first is syncronous, the second is asyncronous.
Correct. Main questions to me here: do I, as a caller, need to care?

My answer would be: none. When used the same way, they should behave in
the same manner. As long as, we get our nice tracebacks when something
went wrong, everything seems find to me.
How is that possible?

def func():
     # Simulate a time consuming calculation.
     time.sleep(10000)
     return 42

# Call func syncronously, blocking until the calculation is done:
x = func()
# Call func asyncronously, without blocking:
y = func()


I think that one of us is missing something here. As I said, I haven't
followed the whole discussion, so it might be me. But on face value, I
don't think what you say is reasonable.

Ah, wait. That is not what I intended and I completely agree with Guido when he says: "I want to be able to *syntactically* tell where the suspension points are in coroutines." http://code.activestate.com/lists/python-dev/135906/

So, it is either:

# Call func syncronously, blocking until the calculation is done:
x = func()

# Call func asyncronously, without blocking:
y = await func()

So, from my perspective, no matter, how many (even zero) suspension points there are in func(), the first variant would still be blocking and the second one not.

Many programmers (when adhering to classical programming) conceive the world as if they call a function and simply do not care about how it works and what it does. The main thing is, it does what it is supposed to do.

Whether this function achieves the goal by working asynchronously or blocking, AND if I, as a programmer, allow the function to work asynchronously, is a completely different matter. That in turn is extremely well reflected by the 'await' keyword (IMHO at least).



Another issue that bothers me, is code reuse. Independent from whether the 'async def' makes sense or not, it would not allow us to reuse asyncio functions as if they were normal functions and vice versa (if I understood that correctly). So, we would have to implement things twice for the asyncio world and the classic world. To me, it would be important to use one function in either world where it suits me better. I am uncertain if that makes sense but right now it does to me.


One last thing regarding 'async def', that came to my mind recently, is that it compares to that necessity of Java to decorate functions with all possible exceptions that could be raised inside. Thankfully, we do not need to do that in Python. IIRC, it is considered bad practice as it ties modules together tighter as they need to be. If I add a single exception down in the traceback, I need to re-add it everywhere where that function is used. That is a mess regarding clean code. Somehow, 'async def' reminds me of that, too, but maybe, I am missing something here.
P.S. This and many other things were discussed at length on the
mailing lists, I suggest you to browse through the archives.
I can imagine that. As said I went through of some of them, but it could
be that I missed some of them as well.

Is there a way to search them through (by not using Google)?
You can download the mailing list archive for the relevant months, and
use your mail client to search them.

Thanks Steven. I already found one on the Web: http://code.activestate.com/lists/python-dev/

And as it seems, I already read through all relevant discussions. :-/
_______________________________________________
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

Reply via email to