Guido van Rossum wrote:
Indeed, in NDB this works great. However tracebacks don't work so great: If you don't catch the exception right away, it takes work to make the tracebacks look right when you catch it a few generator calls down on the (conceptual) stack. I fixed this to some extent in NDB, by passing the traceback explicitly along when setting an exception on a Future;
Was this before or after the recent change that was supposed to improve tracebacks from yield-fram chains? If there's still a problem after that, maybe exception handling in yield-from requires some more work.
But so far when thinking about this recently I have found the goal elusive --
Perhaps you can clear things up by showing some detailed (but still simple enough) example code to handle e.g. a simple web client?
You might like to take a look at this, where I develop a series of examples culminating in a simple multi-threaded server: http://www.cosc.canterbury.ac.nz/greg.ewing/python/generators/yf_current/Exa... Code here: http://www.cosc.canterbury.ac.nz/greg.ewing/python/generators/yf_current/Exa...
somehow it seems there *has* to be a distinction between an operation you just *yield* (this would be waiting for a specific low-level I/O operation) and something you use with yield-from, which returns a value through StopIteration.
It may be worth noting that nothing in my server example uses 'yield' to send or receive values -- yield is only used without argument as a suspension point. But the functions containing the yields *are* called with yield-from and may return values via StopIteration. So I think there are (at least) two distinct ways of using generators, but the distinction isn't quite the one you're making. Rather, we have "coroutines" (don't yield values, do return values) and "iterators" (do yield values, don't return values). Moreover, it's *only* the "coroutine" variety that we need to cater for when designing an async event system. Does that help to alleviate any of your monad-induced headaches? -- Greg