On Tue, 2011-11-08 at 20:43 +1000, Nick Coghlan wrote:
On Tue, Nov 8, 2011 at 6:24 PM, Ron Adam firstname.lastname@example.org wrote:
On Tue, 2011-11-08 at 15:46 +1000, Nick Coghlan wrote:
No, that doesn't make any sense.
Probably because I didn't explain it well enough.
No, it doesn't make any sense because you're taking a symmetric coroutine concept and attempting to apply it to an asymmetric coroutine API design.
I'm not really thinking that way. I'm just looking at what I want to do, and what I'd like to have to do it nicely in python.
*If* this was a symmetric coroutine design (like greenlets), then *yes* it would make sense to offer resume() and throw() as your control flow APIs
(there wouldn't be a suspend() at all in a symmetric design, except perhaps as a convenience wrapper around invoking resume() on the coroutine that called resume() or throw() on you).
You lost me here with suspend() not being needed except as a wrapper around resume(). I think the reason you don't want to do that is because you may want to .resume() multiple sub-coroutines, but you only suspend() the one your in.
The way I see it, coroutines are a bit like little box's where there is a boundary we can't cross in the way we normally would with exceptions. Which is where the throw() method comes in. A throw keyword would go the other direction. (out instead of in.) It wouldn't raise the exception and let it bubble out as in the case of an unexpected error. It would handle expected exception conditions, so continuing from there, does make sense.
My feeling is the reason we don't already have that, has less to do with asymmetric/symmetric design principles, and more to do with not having a strong enough need (possibly until now) to justify a new keyword.
An API design that doesn't require new keywords wouldn't have that limitation. So we could offer both and let the programmer design his coroutines as symmetrical or asymmetrical.
With an asymmetric design, you only have 3 sensible options: terminate naturally, terminate with an exception or suspend execution. Look at the API design again - like the corresponding generator methods, cothread.resume() and cothread.throw() both use "returned normally" to indicate that the coroutine is suspended and still has more to do. If they raise an exception, it means the coroutine is done, either because it failed or because it finished normally (with the latter case being distinguished by a specific exception type, just as it is for generators). You're suggesting it would be reasonable to raise an exception *and* still expect the coroutine to eventually be resumed again. How is the caller of resume() or throw() meant to distinguish that new case from the two terminating cases?
Asymmetric, and symmetric wording is a description of how it's used. We don't necessarily need to limit python programmers to one or the other exclusively.
Let me come up with some working examples. I'm not too far from that now. Then we can discuss and experiment with it in a much more practical way.