On Tue, Nov 8, 2011 at 3:30 PM, Ron Adam email@example.com wrote:
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).