[Python-ideas] Cofunctions: It's alive! Its alive!

Guido van Rossum guido at python.org
Tue Aug 10 17:57:10 CEST 2010


I'm convinced of the utility. I still find the mechanism somehow odd
or clumsy; the need for two new keywords (codef and cocall), a new
builtin (costart), and a new api (__cocall__) doesn't sit well.

Please don't consider this a -1; I think there's something that can be
done (either to my mind or to the proposal :-).

I suppose I should look again at goroutines and see what syntax and
other rules they use.

In the mean time let me ask a few more questions (sorry if these have
been answered before, my attention is focusing in and out of this
thread):

- Is it possible to mix and match yield, yield from, and cocall in the
same function? Should / shouldn't it be?

- Would it be sufficient if codef was a decorator instead of a
keyword? (This new keyword in particular chafes me, since we've been
so successful at overloading 'def' for so many meanings -- functions,
methods, class methods, static methods, properties...)

- If we had cocall, would yield from still be useful? (I suppose yield
from is the thing of choice when using generators-as-iterators, e.g.
when walking a tree. But what bout yield from for coroutines?)

- The cocall keyword eerily reminds me of Fortran. I know that's not
fair, but still...

- The syntax worries me. Your PEP suggests that cocall binds tightly
to an atom. That would mean that if the cofunction is really a
comethod, you'd have to parenthesis it, like cocall (obj.method)(args)
? Huuuu, ugly. Also things lke 'cocall foo' (no call syntax) weird me
out.

- How much of the improved error flagging of codef/cocall can be
obtained by judicious use of decorators and helper functions? (I need
this in Python 2.5 *now*. :-)

--Guido

On Tue, Aug 10, 2010 at 12:22 AM, Greg Ewing
<greg.ewing at canterbury.ac.nz> wrote:
> Guido van Rossum wrote:
>
>> We'll see. I still cannot get my head around why cofunctions are so
>> great.
>
> I think I can offer some evidence. I've been playing around with
> two versions of a discrete-event simulation kernel, one using
> yield-from and the other using cofunctions. Here's the main
> function of one of my test cases. I've introduced a deliberate
> bug -- can you spot it?
>
> def customer(i):
>  print("Customer", i, "arriving at", now())
>  yield from tables.acquire(1)
>  print("Customer", i, "sits down at a table at", now())
>  yield from waiters.acquire(1)
>  print("Customer", i, "orders spam at", now())
>  hold(random.normalvariate(20, 2))
>  waiters.release(1)
>  print("Customer", i, "gets served spam at", now())
>  yield from hold(random.normalvariate(10, 5))
>  print("Customer", i, "finished eating at", now())
>  tables.release(1)
>
> The bug is that the first call to hold() is missing a 'yield
> from' in front of it. If I run this, I don't get any exception --
> it produces plausible-looking but incorrect results.
>
> Here's another version, with a very similar bug in a different
> place -- this time it's the second call to hold() that's missing
> a 'yield from'.
>
> def customer(i):
>  print("Customer", i, "arriving at", now())
>  yield from tables.acquire(1)
>  print("Customer", i, "sits down at a table at", now())
>  yield from waiters.acquire(1)
>  print("Customer", i, "orders spam at", now())
>  yield from hold(random.normalvariate(20, 2))
>  waiters.release(1)
>  print("Customer", i, "gets served spam at", now())
>  hold(random.normalvariate(10, 5))
>  print("Customer", i, "finished eating at", now())
>  tables.release(1)
>
> If I run this one, I do get an exception, but it's a rather
> unhelpful one:
>
> Traceback (most recent call last):
>  File "restaurant2.py", line 35, in <module>
>    run()
>  File
> "/Local/Projects/D/Python/YieldFrom/3.1/YieldFrom-3.1.2/Examples/Simulation/simulation.py",
> line 25, in run
>    next(current_process)
>  File "restaurant2.py", line 32, in customer
>    tables.release(1)
>  File
> "/Local/Projects/D/Python/YieldFrom/3.1/YieldFrom-3.1.2/Examples/Simulation/resource.py",
> line 25, in release
>    wakeup(self.queue[0])
>  File
> "/Local/Projects/D/Python/YieldFrom/3.1/YieldFrom-3.1.2/Examples/Simulation/simulation.py",
> line 34, in wakeup
>    schedule(process, now())
>  File
> "/Local/Projects/D/Python/YieldFrom/3.1/YieldFrom-3.1.2/Examples/Simulation/simulation.py",
> line 16, in schedule
>    heappush(event_queue, (time, process))
> TypeError: unorderable types: generator() < generator()
>
> If you examine the traceback, you'll find that *nowhere* does it
> mention the location where the error actually is! Instead, a
> mysterious error emanates from some place deep inside the scheduler.
> I would hate to have to track down a problem like this in a large
> program.
>
> Here's the equivalent thing using cofunctions, complete with a
> corresponding missing 'cocall':
>
> codef customer(i):
>  print("Customer", i, "arriving at", now())
>  cocall tables.acquire(1)
>  print("Customer", i, "sits down at a table at", now())
>  cocall waiters.acquire(1)
>  print("Customer", i, "orders spam at", now())
>  cocall hold(random.normalvariate(20, 2))
>  cocall waiters.release(1)
>  print("Customer", i, "gets served spam at", now())
>  hold(random.normalvariate(10, 5))
>  print("Customer", i, "finished eating at", now())
>  cocall tables.release(1)
>
> The exception and traceback resulting from this is crystal clear:
>
> Traceback (most recent call last):
>  File "restaurant2.py", line 34, in <module>
>    run()
>  File
> "/Local/Projects/D/Python/YieldFrom/3.1/Cofunctions-3.1.2/Examples/Simulation/simulation.py",
> line 25, in run
>    next(current_process)
>  File "restaurant2.py", line 29, in customer
>    hold(random.normalvariate(10, 5))
> TypeError: Cofunction must be called with cocall or costart
>
> If this doesn't convince you of the utility of cofunctions or
> something like them, I don't know what will.
>
> --
> Greg
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> http://mail.python.org/mailman/listinfo/python-ideas
>



-- 
--Guido van Rossum (python.org/~guido)



More information about the Python-ideas mailing list