[Python-ideas] Cofunctions - Getting away from the iterator protocol

Nick Coghlan ncoghlan at gmail.com
Tue Nov 8 06:46:31 CET 2011

On Tue, Nov 8, 2011 at 3:30 PM, Ron Adam <ron3200 at gmail.com> wrote:
> Generator API.
>   Outside generator   <-->   Inside generator
>      next()                     yield
>      .send()
>      .throw()
> Inverted generator API
>   Outside cothread    <-->   Inside cothread
>      .resume()                  suspend()
>                                 throw()
> Where resume works like yield, (yield to cothread), and suspend() works
> like .send().  Throw() raises an exception at the resume() call,
> like .throw() raises an exception at the yield in a generator.

No, that doesn't make any sense. When the coroutine throws an
exception internally it's done - we don't *want* to preserve the stack
any more, because something broke and we won't be resuming it.
Instead, we let the exception bubble up the stack and if nothing
handles it, we pass it back to the thread that called resume().

The reason we need an explicit throw() is that the data request (or
whatever it was we suspended to wait for) might fail - in that case,
the thread calling resume() needs to be able to indicate this to the
cothread by resuming with an exception.

The flow control parallels are like this:

  Inside the generator/cothread:
    yield -> cothread.suspend() # Wait to be resumed
    return -> return # Finish normally
    raise -> raise  # Bail out with an error

  Outside the generator/cothread
    send() -> resume() # Resume execution normally (optionally providing data)
    throw() -> throw() # Resume execution with an exception

Don't worry about next() in this context, since it's just an alternate
spelling for send(None).


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-ideas mailing list