GorNishanov / coroutines-ts

20 stars 2 forks source link

coroutine_handle<T>::resume should return coroutine_handle<T>::done #3

Closed brycelelbach closed 7 years ago

brycelelbach commented 7 years ago

Calling coroutine_handle<T>::done after calling coroutine_handle<T>::suspend is a common pattern. resume currently returns void. Could we have resume return a bool and be specified to return done()?

GorNishanov commented 7 years ago

I was thinking about that for awhile (two years, or so :) ) and could not justify it to myself. It is definitely the case for generators, but, those are optimized just fine. Do you have a case for doing it for async application of coroutines?

One of the reason against it is that it may inhibit tail call optimizations.

Another common pattern (in async) is that you resume another coroutine from await_suspend. Since await_suspend is followed by a jump to epilogue of a function, it can be replaced with a (potential) stack adjustment and a jump into the next coroutine.

If resume() returns bool, I cannot tail call, since the "done-ness" state of the coroutine I resume may not be the same as "done-ness" state of the caller.

brycelelbach commented 7 years ago

It is definitely the case for generators, but, those are optimized just fine. Do you have a case for doing it for async application of coroutines?

This came up when I was playing around with generators - so I don't have a use case for async applications.

Another common pattern (in async) is that you resume another coroutine from await_suspend. Since await_suspend is followed by a jump to epilogue of a function, it can be replaced with a (potential) stack adjustment and a jump into the next coroutine.

This is something I've wanted to do in HPX's scheduler for a long time. Nat's paper talks about it (he calls it asymmetric switching I believe).

One of the reason against it is that it may inhibit tail call optimizations.

If resume() returns bool, I cannot tail call, since the "done-ness" state of the coroutine I resume may not be the same as "done-ness" state of the caller.

Very interesting, I hadn't thought of this!

I agree with your logic here. I suppose that a separate convenience method for generators (resume_and_check or whatever) could be added, but I don't think I'd want to do that because (1) interface bloat is bad, (2) "async users" might not read the docs and call it in cases where it would kill tail call optimizations and (3) I think most "generator users" will use generic generator classes instead of writing their own.

I'd say go ahead and close this :)