[Python-Dev] PEP 492: What is the real goal?

Paul Sokolovsky pmiscml at gmail.com
Wed Apr 29 23:06:06 CEST 2015


Hello,

On Wed, 29 Apr 2015 20:19:40 +0100
Paul Moore <p.f.moore at gmail.com> wrote:

[]

> Thanks for that. That does look pretty OK. One question, though - it
> uses an asyncio Queue. The original code would work just as well with
> a list, or more accurately, something that wasn't designed for async
> use. So the translation isn't completely equivalent. Also, can I run
> the produce/consume just by calling produce()? My impression is that
> with asyncio I need an event loop - which "traditional" coroutines
> don't need. Nevertheless, the details aren't so important, it was only
> a toy example anyway.

All this confusion stems from the fact that wikipedia article fails to
clearly provide classification dichotomies for coroutines. I suggest
reading Lua coroutine description as much better attempt at
classification: http://www.lua.org/pil/9.1.html . It for example
explicit at mentioning common pitfall: "Some people call asymmetric
coroutine semi-coroutines (because they are not symmetrical, they are
not really co). However, other people use the same term semi-coroutine
to denote a restricted implementation of coroutines". Comparing that
to wikipedia article, you'll notice that it uses "semicoroutine" in
just one of a sense, and well, different people use "semi" part of
a different classification axis.

So, trying to draw a table from Lua's text, there're following 2 axes:

Axis 1: Symmetric vs Asymmetric

Asymmetric coroutines use 2 control flow constructs, akin to
subroutine call and return. (Names vary, return is usually called
yield.) 

Symmetric use only one. You can think of symmetric coroutines only call
or only return, though more un-confusing term is "switch to".

Axis 2: "Lexical" vs "Dynamic"

Naming less standardized. Lua calls its coroutines "tru", while other
- "generators". Others call them "coroutines" vs "generators". But the
real difference is intuitively akin of lexical vs dynamic scoping.
"Lexical" coroutines require explicit marking of each (including
recursive) call to a coroutine. "Dynamic" do not - you can call a
normally looking function, and it suddenly pass control to somewhere
else (another coroutine), about which fact you don't have a clue.


All *four* recombined types above are coroutines, albeit all with
slightly different properties. Symmetric dynamic coroutines are the
most powerful type - as powerful as an abyss. They are what is usually
used to frighten the innocent. Wikipedia shows you example of them.

No sane real-world language uses symmetric coroutines - they're not
useful without continuations, and sane real-world people don't want
to manage continuations manually. Python, Lua, C# use asymmetric
coroutines.

Python and C# use asymmetric "lexical" coroutines - the simplest, and
thus safest type, but which has limitations wrt to doing mind-boggling
things.

Lua has "dynamic" asymmetric coroutines - more powerful, and thus more
dangerous type (you want to look with jaundiced eye at that guy's
framework based on "dynamic" coroutines - you'd better rewrite it from
scratch before you trust it).



-- 
Best regards,
 Paul                          mailto:pmiscml at gmail.com


More information about the Python-Dev mailing list