PEP 492 terminology - (native) coroutine objects

Looking through PEP 492 I dislike the terminology. With generators I can do:
def f(): yield ... g = f() g <generator object f at 0x7fb81dadc798>
So f is a generator function and g is generator. That's all pretty clear and "generator" is IMO a great name. The term "generator function" is also unambiguous for f. With PEP 492 it seems that I would get something like:
async def af(): pass ag = af() ag <coroutine_object object af at 0x7fb81dadc828>
According to the terminology in the PEP af is a coroutine but since the word coroutine also refers to some generators in a looser sense I should use "native coroutine" to disambiguate. ag is a "coroutine object" but again I should use "native coroutine object" to explicitly name the type because without the word "native" it also refers to other things. I think that if the terminology is already ambiguous with related language constructs before it's introduced then it would be better to change it now. The word coroutine (without "native" modifier) is used by the PEP to refer to both generator based coroutines and the new async def functions. I think it's reasonable to use the word as a generic term in this sense. Python's idea of coroutines (both types) doesn't seem to match with the pre-existing general definitions but they are at least generalisations of functions so it can be reasonable to describe them that way loosely. Greg's suggestion to call an async def function (af above) an "async function" seems like a big improvement. It clearly labels the purpose: a function for use in a asynchronous execution probably with the asyncio module. It also matches directly with the syntax: a function prefixed with the word "async". There would be no ambiguity between which of af or ag is referred to by the term. It seems harder to think of a good name for ag though. ag is a wrapper around a suspended call stack with methods to resume the stack so describing what is is doesn't lead to anything helpful. OTOH the purpose of ag is often described as implementing a "minithread" so the word "minithread" makes intuitive sense to me. That way async code is done by writing async functions that return minithreads. An event loop schedules the minthreads etc. (I'm trying to imagine explaining this to someone...) I'm not sure what the best word is for a coroutine object but the current terminology clearly has room for improvement. For a start using the word "object" in the name of a type is a bit rubbish in a language where everything is an object. Worse the PEP is reusing words that have already been used with different meanings so that it's already ambiguous. A concrete builtin language type such as the coroutine object deserves a good, short, one-word name that will not be confused with other things. -- Oscar

On 04/30/2015 04:37 PM, Oscar Benjamin wrote:
With PEP 492 it seems that I would get something like:
>async def af(): pass >ag = af() >ag <coroutine_object object af at 0x7fb81dadc828>
It seems harder to think of a good name for ag though.
A waiter? or awaiter? As in a-wait-ing an awaiter. Maybe there's a restaurant/food way of describing how it works. :-) I'm not sure I have the use correct. But I think we need to use "await af()" when calling an async function. Cheers, Ron

Ron Adam wrote:
A waiter? or awaiter?
As in a-wait-ing an awaiter.
The waiter would be the function executing the await operator, not the thing it's operating on. In a restaurant, waiters wait on customers. But calling an awaitable object a "customer" doesn't seem right at all. -- Greg

On Apr 30, 2015, at 22:24, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Ron Adam wrote:
A waiter? or awaiter? As in a-wait-ing an awaiter.
The waiter would be the function executing the await operator, not the thing it's operating on.
In a restaurant, waiters wait on customers. But calling an awaitable object a "customer" doesn't seem right at all.
Well, the only thing in the restaurant besides the waiter and the customers is the Vikings, so I guess the restaurant metaphor doesn't work... Anyway, if I understand the problem, the main confusion is that we use "coroutine" both to mean a thing that can be suspended and resumed, and a function that returns such a thing. Why not just "coroutine" and "coroutine function", just as with "generator" and "generator function". If the issue is that there are other things that are coroutines besides the coroutine type... well, there are plenty of things that are iterators that are all of unrelated types, and has anyone ever been confused by that? (Of course people have been confused by iterator vs. iterable, but that's a different issue, and one that doesn't have a parallel here.)
-- Greg _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/

On 1 May 2015 at 12:24, Andrew Barnert via Python-ideas <python-ideas@python.org> wrote:
Anyway, if I understand the problem, the main confusion is that we use "coroutine" both to mean a thing that can be suspended and resumed, and a function that returns such a thing. Why not just "coroutine" and "coroutine function", just as with "generator" and "generator function".
That's the terminology in the asyncio docs I guess: https://docs.python.org/3/library/asyncio-task.html#coroutine ... except that there it is referring to decorated generator functions. That feels like a category error to me because coroutines are a generalisation a functions so if anything is the coroutine itself then it is the async def function rather than the object it returns but I guess if that's what's already being used.
If the issue is that there are other things that are coroutines besides the coroutine type... well, there are plenty of things that are iterators that are all of unrelated types, and has anyone ever been confused by that? (Of course people have been confused by iterator vs. iterable, but that's a different issue, and one that doesn't have a parallel here.)
There is no concrete "iterator" type. The use of iterator as a type is explicitly intended to refer to a range of different types of objects analogous to using an interface in Java. The PEP proposes at the same time that the word coroutine should be both a generic term for objects exposing a certain interface and also the term for a specific language construct: the function resulting from an async def statement. So if I say that something is a "coroutine" it's really not clear what that means. It could mean an an asyncio.coroutine generator function, it could mean an async def function or it could mean both. Worse it could mean the object returned by either of those types of functions. -- Oscar

On Fri, May 01, 2015 at 12:49:44PM +0100, Oscar Benjamin wrote:
So if I say that something is a "coroutine" it's really not clear what that means. It could mean an an asyncio.coroutine generator function, it could mean an async def function or it could mean both. Worse it could mean the object returned by either of those types of functions.
I'm sympathetic to your concerns, and I raised a similar issue earlier. But, it's not entirely without precedence. We already use "generator" to mean both the generator-function and the generator-iterator returned from the generator-function. We use "decorator" to mean both the function and the @ syntax. Sometimes we distinguish between classes and objects (instances), sometimes we say that classes are objects, and sometimes we say that classes are instances of the metaclass. "Method" can refer to either the function object inside a class or the method instance after the descriptor protocol has run. And of course, once you start comparing terms from multiple languages, the whole thing just gets worse (contrast what Haskell considers a functor with what C++ considers a functor). It's regretable when language is ambiguous, but sometimes a little bit of ambiguity is the lesser of the evils. Human beings are usually good at interpreting that given sufficient context and understanding. If there is no good alternative to coroutine, we'll need some good documentation to disambiguate the meanings. -- Steve

On May 1, 2015, at 04:49, Oscar Benjamin <oscar.j.benjamin@gmail.com> wrote:
On 1 May 2015 at 12:24, Andrew Barnert via Python-ideas <python-ideas@python.org> wrote:
Anyway, if I understand the problem, the main confusion is that we use "coroutine" both to mean a thing that can be suspended and resumed, and a function that returns such a thing. Why not just "coroutine" and "coroutine function", just as with "generator" and "generator function".
That's the terminology in the asyncio docs I guess: https://docs.python.org/3/library/asyncio-task.html#coroutine ... except that there it is referring to decorated generator functions.
That feels like a category error to me because coroutines are a generalisation a functions so if anything is the coroutine itself then it is the async def function rather than the object it returns but I guess if that's what's already being used.
I agree with this last point, and the "cofunction" terminology handled that better... In practice, I don't think this kind of thing usually causes much of a problem. For example, when first learning Swift, you have to learn that an iterator isn't really an iterator, it's a generalized index, but within the first day you've already forgotten the issue and you're just using iterators. It's no worse than switching back and forth between Self and C++, which both have things that as reasonably accurately called "iterators" but nevertheless work completely differently. But maybe the best thing to do here is look at the terminology used in the F# papers (which I think introduced the await/async idea), and then see if the same terminology is used in practice in more widespread languages like C# that borrowed the idea, and if so just go with that. Even if it's wrong, it'll be the same wrong that everyone else is learning, and if we don't have something clearly better...
If the issue is that there are other things that are coroutines besides the coroutine type... well, there are plenty of things that are iterators that are all of unrelated types, and has anyone ever been confused by that? (Of course people have been confused by iterator vs. iterable, but that's a different issue, and one that doesn't have a parallel here.)
There is no concrete "iterator" type. The use of iterator as a type is explicitly intended to refer to a range of different types of objects analogous to using an interface in Java.
The PEP proposes at the same time that the word coroutine should be both a generic term for objects exposing a certain interface and also the term for a specific language construct: the function resulting from an async def statement.
So if I say that something is a "coroutine" it's really not clear what that means. It could mean an an asyncio.coroutine generator function, it could mean an async def function or it could mean both. Worse it could mean the object returned by either of those types of functions.
-- Oscar _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/

On 05/01/2015 01:24 AM, Greg Ewing wrote:
Ron Adam wrote:
A waiter? or awaiter?
As in a-wait-ing an awaiter.
The waiter would be the function executing the await operator, not the thing it's operating on.
In a restaurant, waiters wait on customers. But calling an awaitable object a "customer" doesn't seem right at all.
Guido has been using awaitable over in python-dev. Lets see how that works... In a restaurant, a waiter serves food. An awaitable is a specific kind of waiter.. One that may wait for other waiters to serve their customers (table) food before they serve your food, even though your order may have happened before another tables order was taken. Each awaitable only serves one table, and never takes orders or serves food to any other table. In a normal python restaurant without awaitables, each waiter must takes your order, and then serve your food, before any other waiter can take an order and serve it's customer food. The consumer is the caller of the expression. We can think of restaurant tables as function frames. The "awaiter" keyword here just makes sure an awaiter is qualified to serve food in this async restaurant. We don't want the Vikings serving food, do we. ;-) Of course someone needs to get the tables filled. That's where the maitre d' comes in. He uses an "async for", or "async with", statement to fill all the tables with customers and keeps them happy. That's not perfect, but I think it gets the general concepts correct and makes them easier to think about. (At least for me.) Cheers, Ron
participants (5)
-
Andrew Barnert
-
Greg Ewing
-
Oscar Benjamin
-
Ron Adam
-
Steven D'Aprano