Re: Implement async/await using Fiber
On 05/20/2016 12:56 PM, Yuxuan Shui wrote: > On Friday, 20 May 2016 at 06:40:42 UTC, Jacob Carlborg wrote: >> On 2016-05-20 04:14, Yuxuan Shui wrote: >> >>> Hmm... This could work. But I'm not satisfied with this solution. What >>> if I have multiple yield sites in the fiber, and each have different >>> return types? >>> >>> Maybe I should use a Variant? >> >> I think you can view "yield" as a form of "return". If you cannot >> return different types from a function (without it being a template) >> it would be weird if you could yield different types. > > But this is yield as in coroutine, not yield as in generators. Those > yields doesn't return value to the caller of the fiber. > > Let's have an example: > > void func() { > string a = wait_for_user_input(); > int b = wait_for_user_to_click_a_button(); > } > > Those two wait()s could use yield internally to transfer execution back > to the caller and wait for input. But it's difficult with current dlang > fiber because there's no (elegant) way to pass data (preferably with > different types) while transferring executing to/from fibers. Agreed. Fibers are not a language construct. One has to do what std.concurrency.Generator does internally. In this case, we need another layer of function calls. (I could have used Generator below and I could avoid creating a fiber for each call by moving the fibers to module-scope.) import core.thread; void input_fiber(ref string input) { while (true) { input = "hello"; Fiber.yield(); } } string wait_for_user_input() { string input; auto f = new Fiber(() => input_fiber(input)); f.call(); return input; } void click_fiber(ref int button) { while (true) { button = 42; Fiber.yield(); } } int wait_for_user_to_click_a_button() { int button; auto f = new Fiber(() => click_fiber(button)); f.call(); return button; } void func() { foreach (i; 0 .. 10) { string a = wait_for_user_input(); assert(a == "hello"); int b = wait_for_user_to_click_a_button(); assert(b == 42); } } void main() { func(); } Ali
Re: Implement async/await using Fiber
On Friday, 20 May 2016 at 06:40:42 UTC, Jacob Carlborg wrote: On 2016-05-20 04:14, Yuxuan Shui wrote: Hmm... This could work. But I'm not satisfied with this solution. What if I have multiple yield sites in the fiber, and each have different return types? Maybe I should use a Variant? I think you can view "yield" as a form of "return". If you cannot return different types from a function (without it being a template) it would be weird if you could yield different types. But this is yield as in coroutine, not yield as in generators. Those yields doesn't return value to the caller of the fiber. Let's have an example: void func() { string a = wait_for_user_input(); int b = wait_for_user_to_click_a_button(); } Those two wait()s could use yield internally to transfer execution back to the caller and wait for input. But it's difficult with current dlang fiber because there's no (elegant) way to pass data (preferably with different types) while transferring executing to/from fibers.
Re: Implement async/await using Fiber
On 2016-05-20 04:14, Yuxuan Shui wrote: Hmm... This could work. But I'm not satisfied with this solution. What if I have multiple yield sites in the fiber, and each have different return types? Maybe I should use a Variant? I think you can view "yield" as a form of "return". If you cannot return different types from a function (without it being a template) it would be weird if you could yield different types. -- /Jacob Carlborg
Re: Implement async/await using Fiber
On Thursday, 19 May 2016 at 23:42:03 UTC, Ali Çehreli wrote: On 05/19/2016 12:57 PM, Yuxuan Shui wrote: [...] You can use a delegate that takes a ref parameter: import std.stdio; import core.thread; void fiberFunc(ref string y) { y = "produced_by_fiberFunc"; Fiber.yield(); } void main() { string data; auto f = new Fiber(() => fiberFunc(data)); f.call(); writefln("Writing in main: %s", data); } Prints: Writing in main: produced_by_fiberFunc Also see std.concurrency.Generator. Both methods appear here: http://ddili.org/ders/d.en/fibers.html Ali Hmm... This could work. But I'm not satisfied with this solution. What if I have multiple yield sites in the fiber, and each have different return types? Maybe I should use a Variant?
Re: Implement async/await using Fiber
On 05/19/2016 04:42 PM, Ali Çehreli wrote: > You can use a delegate that takes a ref parameter: Correction: You can use a delegate that calls a function that takes a ref parameter. Ali
Re: Implement async/await using Fiber
On 05/19/2016 12:57 PM, Yuxuan Shui wrote: I find this difficult because I can't passing data via Fiber.yield/Fiber.call pair. e.g. I want something like: void fiberFunc() { //Add some file descriptor to main loop string y = Fiber.yield(); writeln(y); } auto f = new Fiber(&fiberFunc); f.call(); mainloop { if (fd_readable) f.call(fd.rawRead()); } I can probably using a derived fiber class and pass the result via class members, but that seems clumsy and not very general. Any ideas? You can use a delegate that takes a ref parameter: import std.stdio; import core.thread; void fiberFunc(ref string y) { y = "produced_by_fiberFunc"; Fiber.yield(); } void main() { string data; auto f = new Fiber(() => fiberFunc(data)); f.call(); writefln("Writing in main: %s", data); } Prints: Writing in main: produced_by_fiberFunc Also see std.concurrency.Generator. Both methods appear here: http://ddili.org/ders/d.en/fibers.html Ali
Implement async/await using Fiber
I find this difficult because I can't passing data via Fiber.yield/Fiber.call pair. e.g. I want something like: void fiberFunc() { //Add some file descriptor to main loop string y = Fiber.yield(); writeln(y); } auto f = new Fiber(&fiberFunc); f.call(); mainloop { if (fd_readable) f.call(fd.rawRead()); } I can probably using a derived fiber class and pass the result via class members, but that seems clumsy and not very general. Any ideas?