Re: Implement async/await using Fiber

2016-05-20 Thread Ali Çehreli via Digitalmars-d-learn

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

2016-05-20 Thread Yuxuan Shui via Digitalmars-d-learn

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

2016-05-19 Thread Jacob Carlborg via Digitalmars-d-learn

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

2016-05-19 Thread Yuxuan Shui via Digitalmars-d-learn

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

2016-05-19 Thread Ali Çehreli via Digitalmars-d-learn

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

2016-05-19 Thread Ali Çehreli via Digitalmars-d-learn

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

2016-05-19 Thread Yuxuan Shui via Digitalmars-d-learn
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?