www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: Full closures for D

reply Mikola Lysenko <mclysenk mtu.edu> writes:
I'm excited.  For the first time it is now possible to do futures in 7 lines of
code:

T delegate() future(T)(lazy T expr)
{
    T res;
    auto t = new Thread({res = expr();});
    t.start;
    return { t.wait; return res; }
}


Which could then be used as follows:

auto hard_result = future( hard_expression );

// Do stuff ...

use_result(hard_result());
Nov 05 2007
next sibling parent reply "Craig Black" <cblack ara.com> writes:
"Mikola Lysenko" <mclysenk mtu.edu> wrote in message 
news:fgns3v$1b13$1 digitalmars.com...
 I'm excited.  For the first time it is now possible to do futures in 7 
 lines of code:

 T delegate() future(T)(lazy T expr)
 {
    T res;
    auto t = new Thread({res = expr();});
    t.start;
    return { t.wait; return res; }
 }


 Which could then be used as follows:

 auto hard_result = future( hard_expression );

 // Do stuff ...

 use_result(hard_result());

Very cool stuff! Did you test this code to see if it actually works? A little off topic, but I was looking at your code and wondering if "lazy" always means that the expression becomes a delegate? When a template is used, the compiler could embed the expression directly rather than creating a delegate. Since D is big on compile-time optimization, I was wondering if it does this. -Craig
Nov 05 2007
parent reply BCS <BCS pathlink.com> writes:
Craig Black wrote:
 "Mikola Lysenko" <mclysenk mtu.edu> wrote in message 
 news:fgns3v$1b13$1 digitalmars.com...
 
I'm excited.  For the first time it is now possible to do futures in 7 
lines of code:

T delegate() future(T)(lazy T expr)
{
   T res;
   auto t = new Thread({res = expr();});
   t.start;
   return { t.wait; return res; }
}


Which could then be used as follows:

auto hard_result = future( hard_expression );

// Do stuff ...

use_result(hard_result());

Very cool stuff! Did you test this code to see if it actually works? A little off topic, but I was looking at your code and wondering if "lazy" always means that the expression becomes a delegate? When a template is used, the compiler could embed the expression directly rather than creating a delegate. Since D is big on compile-time optimization, I was wondering if it does this. -Craig

string mixins are fun: typeof(mixin(expr)) delegate() future(char[] expr)() { typeof(mixin(expr)) res; auto t = new Thread({res = mixin(expr);}); t.start; return { t.wait; return res; } } auto hard_result = future!("hard_expression"); // Do stuff ... use_result(hard_result()); NOTE: this runs into the issue that there is no way to get a template to play with the local variables of a function. If there were a way to do this I can think of a number of very cool things that could be done.
Nov 05 2007
next sibling parent reply Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
BCS wrote:

 string mixins are fun:
 
 typeof(mixin(expr)) delegate() future(char[] expr)()
 {
     typeof(mixin(expr)) res;
     auto t = new Thread({res = mixin(expr);});
     t.start;
     return { t.wait; return res; }
 }
 
 auto hard_result = future!("hard_expression");
 // Do stuff ...
 use_result(hard_result());
 
 
 NOTE: this runs into the issue that there is no way to get a template to
 play with the local variables of a function. If there were a way to do
 this I can think of a number of very cool things that could be done.

Yea, bummer :| I would have expected this to work: char[] bar(char[] foo) { char[] tmp; tmp ~= "alias "; foreach(p; foo) if (p == ',') tmp ~= ", alias "; else tmp ~= p; return tmp; } template future(char[] aliases, char[] expr) { mixin(typeof(mixin(expr)).stringof ~ ` delegate() future(` ~ bar(aliases) ~ `)() { ` ~ typeof(mixin(expr)).stringof ~ ` res; auto t = new Thread({res = mixin(expr);}); t.start;   return { t.wait; return res; }; }`); } void main() { int a = 1, b = 2; auto hard_result = future!("a,b", "a+b+39")!()(); } Seems like Walter has at least two bugs to solve before that happens..
Nov 05 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Jari-Matti Mäkelä wrote:
 BCS wrote:
 
 string mixins are fun:

 typeof(mixin(expr)) delegate() future(char[] expr)()
 {
     typeof(mixin(expr)) res;
     auto t = new Thread({res = mixin(expr);});
     t.start;
     return { t.wait; return res; }
 }

 auto hard_result = future!("hard_expression");
 // Do stuff ...
 use_result(hard_result());


 NOTE: this runs into the issue that there is no way to get a template to
 play with the local variables of a function. If there were a way to do
 this I can think of a number of very cool things that could be done.

Yea, bummer :| I would have expected this to work: char[] bar(char[] foo) { char[] tmp; tmp ~= "alias "; foreach(p; foo) if (p == ',') tmp ~= ", alias "; else tmp ~= p; return tmp; } template future(char[] aliases, char[] expr) { mixin(typeof(mixin(expr)).stringof ~ ` delegate() future(` ~ bar(aliases) ~ `)() { ` ~ typeof(mixin(expr)).stringof ~ ` res; auto t = new Thread({res = mixin(expr);}); t.start; return { t.wait; return res; }; }`); } void main() { int a = 1, b = 2; auto hard_result = future!("a,b", "a+b+39")!()(); } Seems like Walter has at least two bugs to solve before that happens..

It's not a bug that future can't see a or b. They're called "visibility rules" and we have them for a reason, boy. Without rules, there's just *chaos* and chaos is... ugh, I don't even want to *think* about it. You could cheat and do this, though: void main() { int a = 1, b = 2; auto hard_result = mixin(future("a,b","a+b+39")); } Since the string mixin gets expanded into the context of the function. But, as you can see, it's ugly and clumsy. Just stick to lazy arguments for Pete's sake :P -- Daniel
Nov 05 2007
next sibling parent reply BCS <BCS pathlink.com> writes:
Daniel Keep wrote:
 
 It's not a bug that future can't see a or b.  They're called "visibility
 rules" and we have them for a reason, boy.  Without rules, there's just
 *chaos* and chaos is... ugh, I don't even want to *think* about it.
 

It would be nice to have a way to say "reach around these rules right now"
Nov 05 2007
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
BCS wrote:
 Daniel Keep wrote:
 It's not a bug that future can't see a or b.  They're called "visibility
 rules" and we have them for a reason, boy.  Without rules, there's just
 *chaos* and chaos is... ugh, I don't even want to *think* about it.

It would be nice to have a way to say "reach around these rules right now"

I believe this is what AST macros will be for. :) -- Daniel
Nov 05 2007
prev sibling parent Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Daniel Keep wrote:

 
 
 Jari-Matti Mäkelä wrote:
 BCS wrote:
 
 string mixins are fun:

 typeof(mixin(expr)) delegate() future(char[] expr)()
 {
     typeof(mixin(expr)) res;
     auto t = new Thread({res = mixin(expr);});
     t.start;
     return { t.wait; return res; }
 }

 auto hard_result = future!("hard_expression");
 // Do stuff ...
 use_result(hard_result());


 NOTE: this runs into the issue that there is no way to get a template to
 play with the local variables of a function. If there were a way to do
 this I can think of a number of very cool things that could be done.

Yea, bummer :| I would have expected this to work: char[] bar(char[] foo) { char[] tmp; tmp ~= "alias "; foreach(p; foo) if (p == ',') tmp ~= ", alias "; else tmp ~= p; return tmp; } template future(char[] aliases, char[] expr) { mixin(typeof(mixin(expr)).stringof ~ ` delegate() future(` ~ bar(aliases) ~ `)() { ` ~ typeof(mixin(expr)).stringof ~ ` res; auto t = new Thread({res = mixin(expr);}); t.start; return { t.wait; return res; }; }`); } void main() { int a = 1, b = 2; auto hard_result = future!("a,b", "a+b+39")!()(); } Seems like Walter has at least two bugs to solve before that happens..

It's not a bug that future can't see a or b. They're called "visibility rules" and we have them for a reason, boy. Without rules, there's just *chaos* and chaos is... ugh, I don't even want to *think* about it.

You probably didn't notice but I used alias parameters there. So it should be very much possible to refer to the variables after that. Made a small bug though, should have been
   auto hard_result = future!("a,b", "a+b+39")!(a,b)();


or perhaps char[] Future(char[] a, char[] b) { return `future!("` ~ a ~ `","` ~ b ~ `")!(` ~ a ~ `)`; } auto hard_result = mixin(Future("a,b", "a+b+39"))();
 You could cheat and do this, though:
 
 void main() {
   int a = 1, b = 2;
   auto hard_result = mixin(future("a,b","a+b+39"));
 }
 
 Since the string mixin gets expanded into the context of the function.

Alias parameters work much better.
Nov 06 2007
prev sibling parent Kevin Bealer <kevinbealer gmail.com> writes:
My futurism library has support for the kind of thing you are describing.  Two
of
the several syntaxes it supports are shown here; both of these are for reading
two
disk files in parallel.

    // Read the contents of two files in parallel:

    char[] read_file(char[] fname)
    {
        return cast(char[]) read(fname1);
    }

    auto f1 = make_future(& read_file, fname1);
    auto f2 = make_future(& read_file, fname2);

    // Get the results - will block until each read() is done.
    char[] fv1 = f1.value;
    char[] fv2 = f2.value;

And this:

    alias Future!(char[]) FString;

    char[] fname1 = "a.txt", fname2 = "b.txt";

    FString f1 = new FString({ return cast(char[]) read(fname1); });
    FString f2 = new FString({ return cast(char[]) read(fname2); });

    // Get the results - will block until each read() is done.
    char[] fv1 = f1.value;
    char[] fv2 = f2.value;

You can find it at dsource.org/projects/futurism.  It's a few more than 7 lines,
but a lot of it is thread pool management and so on.

It took a bit of trial and error and some newsgroup chat to nail down all the
syntax for capturing arguments like the fname1 shown here.  (Maybe some of that
would not be needed now that full closures exist.)

Kevin
Nov 05 2007
prev sibling parent torhu <no spam.invalid> writes:
Mikola Lysenko wrote:
 I'm excited.  For the first time it is now possible to do futures in 7 lines
of code:
 
 T delegate() future(T)(lazy T expr)
 {
     T res;
     auto t = new Thread({res = expr();});
     t.start;
     return { t.wait; return res; }
 }
 
 
 Which could then be used as follows:
 
 auto hard_result = future( hard_expression );
 
 // Do stuff ...
 
 use_result(hard_result());

I tested your code and got this: Unhandled Exception: EXCEPTION_ACCESS_VIOLATION(0xc0000005) at (0x00930f80) ->us #0 ?? () #1 0x00405191 in MFZi std.thread.Thread.run () from thread #2 0x0040fd99 in ___threadstartex 4 () from threadex -> Something's wrong, but I'm not sure what. res is correctly put on the heap, so it's not that.
Nov 05 2007