Generator/Coroutiine Ontology (was async/await in Python)

On Sat, Apr 18, 2015 at 12:28 AM, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
I am also interested in this topic --- from the other side. As a teacher of python it is my finding that the terminology/documentation around generators is rather chaotic and messy. Basically given: def foo(): yield 1 bar = foo() what do we call foo and what do we call bar? It is suggested that foo is "generator-function" and bar is "generator-object" Unfortunately python does not aid this distinction; witness
I asked about this on the python list http://code.activestate.com/lists/python-list/682286/ And it seems that many more dark corners emerged in the docs on this subject in that discussion. Should I start a separate thread?

Hi Rustom, On 2015-04-18 12:48 AM, Rustom Mody wrote:
inspect.isfunction() inspect.isgenerator() inspect.isgeneratorfunction()
I think that yes, this has to be a different thread. Async/await thread is specifically to discuss PEP 492. Thanks, Yury

On Saturday, April 18, 2015 at 11:07:24 AM UTC+5:30, Yury Selivanov wrote:
This is confusing... I replied to your mail and changed the subject. Both gmail and googlegroups show a new thread created So how it is in other newsreaders/mail clients I dont know

On Apr 17, 2015, at 21:48, Rustom Mody <rustompmody@gmail.com> wrote:
I assume you're ok with the type(bar); the type of a generator object is named "generator", just like the type of a bound method object is named "method" and the type of an integer object is named "int", and so on. So presumably you don't like the former. But what about it? The only thing I can imagine is the fact that, even though a generator function is conceptually a "subkind" of function, there is no generator function subtype of the function type? But so what? There's no closure function subtype, just functions whose closure is nonempty; there's no positive int subtype, just ints whose value is positive; etc. And likewise, there's no callable supertype that function and method (and other things) inherit. If there were some additional API that a generator function should provide that other functions don't (or some implementation reason that makes it worth subclassing for convenience, I suppose), that would be a good reason for needing a subtype. For example, generator a subtype of iterator, just as file is, because they both add new methods that don't make sense for the base iterator type. But just wanting repr(type(x)) to give you more information about x, that's not a good reason to add a subtype. So, it seems to me like both of these are returning something you should reasonably expect. Although you didn't bring this up here, I'll bet somewhere in that thread you point out that it's unfortunate that, in loose usage, people sometimes call a generator function--or, more often, the source code defining one--a generator, in the same way they sometimes call the source code defining a function a function, but there's ambiguity like that all over the natural language we use to talk about programming; as long as there are terms we can use when we need to be strict, it's rarely a problem. And I think we have such terms here: a generator function is the kind of function used to implement generator objects, while are a kind (and indeed a subtype) of iterator objects. Changing the strict names from the obvious ones to something that nobody can get wrong--like calling function definitions "code defs" so nobody loosely says "function" anymore--wouldn't be a win. Besides, the generator PEP and its discussion went over this in detail, and IIRC Guido's conclusion could be paraphrased as "I think this is FUD, but I don't think we'll be able to prove that except by looking at actual experience in a few years". In actual experience, I haven't seen anyone stumble over this except if they don't understand the basic generator abstraction at all. (I can't speak to whether that makes it harder to teach that abstraction to novices or not, but I would guess it only really affects the ones who are "reading ahead in class", who you can mostly count on to get things or ask good questions, because you can just avoid the loose usage entirely in class.)

Will write the points later but for now... On Sat, Apr 18, 2015 at 11:35 AM, Andrew Barnert wrote:
Yes its this loose usage not just across the net but in the docs that in my experience are giving a great deal of trouble to noobs. Just to be clear: I am not talking about changing the language at all¹; just streamlining the docs. I believe we just should take the current way of def-ining generators as a given. Then the discussions can be more meaningful and less FUD-ly I will write up a summary of that thread... ----------------- ¹ Well with the exception of areas where the line between semantics and docs is hazy eg help() and introspection

On 18 April 2015 at 16:05, Andrew Barnert <abarnert@yahoo.com.dmarc.invalid> wrote:
Catching up on email following PyCon travel, there's a reasonable question here related to the repr() of "foo" itself: >>> def foo(): ... yield 1 ... >>> foo <function foo at 0x7f7dad9f7bf8> >>> import dis >>> dis.show_code(foo) Name: foo Filename: <stdin> Argument count: 0 Kw-only arguments: 0 Number of locals: 0 Stack size: 1 Flags: OPTIMIZED, NEWLOCALS, GENERATOR, NOFREE Constants: 0: None 1: 1 Modifying the repr of a function based on whether or not the GENERATOR flag was set on the code object would be quite doable. For example, the above could be: >>> foo <function foo at 0x7f7dad9f7bf8 (generator)> type(foo) would still be unchanged, we'd just be exposing some additional info in the value repr(). While it's a less significant behavioural difference than being a generator function, a non-empty closure could conceivably also be reported in the repr(): <function foo at 0x7f7dad9f7bf8 (closure)> <function foo at 0x7f7dad9f7bf8 (closure,generator)> Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 25 April 2015 at 16:02, Nick Coghlan <ncoghlan@gmail.com> wrote:
I like this suggestion. Doing it for the await changes as well would be great. -Rob -- Robert Collins <rbtcollins@hp.com> Distinguished Technologist HP Converged Cloud

On 25 April 2015 at 14:51, Guido van Rossum <guido@python.org> wrote:
+1
RFE filed as http://bugs.python.org/issue24056 Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

Hi Rustom, On 2015-04-18 12:48 AM, Rustom Mody wrote:
inspect.isfunction() inspect.isgenerator() inspect.isgeneratorfunction()
I think that yes, this has to be a different thread. Async/await thread is specifically to discuss PEP 492. Thanks, Yury

On Saturday, April 18, 2015 at 11:07:24 AM UTC+5:30, Yury Selivanov wrote:
This is confusing... I replied to your mail and changed the subject. Both gmail and googlegroups show a new thread created So how it is in other newsreaders/mail clients I dont know

On Apr 17, 2015, at 21:48, Rustom Mody <rustompmody@gmail.com> wrote:
I assume you're ok with the type(bar); the type of a generator object is named "generator", just like the type of a bound method object is named "method" and the type of an integer object is named "int", and so on. So presumably you don't like the former. But what about it? The only thing I can imagine is the fact that, even though a generator function is conceptually a "subkind" of function, there is no generator function subtype of the function type? But so what? There's no closure function subtype, just functions whose closure is nonempty; there's no positive int subtype, just ints whose value is positive; etc. And likewise, there's no callable supertype that function and method (and other things) inherit. If there were some additional API that a generator function should provide that other functions don't (or some implementation reason that makes it worth subclassing for convenience, I suppose), that would be a good reason for needing a subtype. For example, generator a subtype of iterator, just as file is, because they both add new methods that don't make sense for the base iterator type. But just wanting repr(type(x)) to give you more information about x, that's not a good reason to add a subtype. So, it seems to me like both of these are returning something you should reasonably expect. Although you didn't bring this up here, I'll bet somewhere in that thread you point out that it's unfortunate that, in loose usage, people sometimes call a generator function--or, more often, the source code defining one--a generator, in the same way they sometimes call the source code defining a function a function, but there's ambiguity like that all over the natural language we use to talk about programming; as long as there are terms we can use when we need to be strict, it's rarely a problem. And I think we have such terms here: a generator function is the kind of function used to implement generator objects, while are a kind (and indeed a subtype) of iterator objects. Changing the strict names from the obvious ones to something that nobody can get wrong--like calling function definitions "code defs" so nobody loosely says "function" anymore--wouldn't be a win. Besides, the generator PEP and its discussion went over this in detail, and IIRC Guido's conclusion could be paraphrased as "I think this is FUD, but I don't think we'll be able to prove that except by looking at actual experience in a few years". In actual experience, I haven't seen anyone stumble over this except if they don't understand the basic generator abstraction at all. (I can't speak to whether that makes it harder to teach that abstraction to novices or not, but I would guess it only really affects the ones who are "reading ahead in class", who you can mostly count on to get things or ask good questions, because you can just avoid the loose usage entirely in class.)

Will write the points later but for now... On Sat, Apr 18, 2015 at 11:35 AM, Andrew Barnert wrote:
Yes its this loose usage not just across the net but in the docs that in my experience are giving a great deal of trouble to noobs. Just to be clear: I am not talking about changing the language at all¹; just streamlining the docs. I believe we just should take the current way of def-ining generators as a given. Then the discussions can be more meaningful and less FUD-ly I will write up a summary of that thread... ----------------- ¹ Well with the exception of areas where the line between semantics and docs is hazy eg help() and introspection

On 18 April 2015 at 16:05, Andrew Barnert <abarnert@yahoo.com.dmarc.invalid> wrote:
Catching up on email following PyCon travel, there's a reasonable question here related to the repr() of "foo" itself: >>> def foo(): ... yield 1 ... >>> foo <function foo at 0x7f7dad9f7bf8> >>> import dis >>> dis.show_code(foo) Name: foo Filename: <stdin> Argument count: 0 Kw-only arguments: 0 Number of locals: 0 Stack size: 1 Flags: OPTIMIZED, NEWLOCALS, GENERATOR, NOFREE Constants: 0: None 1: 1 Modifying the repr of a function based on whether or not the GENERATOR flag was set on the code object would be quite doable. For example, the above could be: >>> foo <function foo at 0x7f7dad9f7bf8 (generator)> type(foo) would still be unchanged, we'd just be exposing some additional info in the value repr(). While it's a less significant behavioural difference than being a generator function, a non-empty closure could conceivably also be reported in the repr(): <function foo at 0x7f7dad9f7bf8 (closure)> <function foo at 0x7f7dad9f7bf8 (closure,generator)> Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 25 April 2015 at 16:02, Nick Coghlan <ncoghlan@gmail.com> wrote:
I like this suggestion. Doing it for the await changes as well would be great. -Rob -- Robert Collins <rbtcollins@hp.com> Distinguished Technologist HP Converged Cloud

On 25 April 2015 at 14:51, Guido van Rossum <guido@python.org> wrote:
+1
RFE filed as http://bugs.python.org/issue24056 Cheers, Nick.
-- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
participants (6)
-
Andrew Barnert
-
Guido van Rossum
-
Nick Coghlan
-
Robert Collins
-
Rustom Mody
-
Yury Selivanov