www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Forcing closures to come on the stack

reply Mehrdad <wfunction hotmail.com> writes:
I just made something I thought I'd share.

It's great for those times when the compiler decides to randomly put a 
closure on the heap.

The usage is pretty simple:

     int x = 5;
     auto adder5 = mixin(closure!x(q{(int a) { return a + x; }}));
     assert(adder5(10) == 15);

It returns a callable struct whose body is the given string; the 
template parameters are the variables under closure (in this case, x).

The generated code looks like (minus a little beautification on my part):

     (delegate(ref int x) {
         static struct State {
             int* px;
              property ref int x() { return *this.px; }
             auto opCall(int a) { return a + x; }
         }
         State tmp;
         tmp.px = &x;
         return tmp;
     })(x)

So when you assign it to something, that something becomes a struct with 
opCall overloaded. You can then take the address of opCall on the 
struct, and you get a delegate.

Thoughts?

----------------------------------------------
  // Code:

string closure(States...)(string argsAndBody)
{
     string stateArgs = null, stateVars = null, stateProps = null, 
setStateVars = null;
     alias staticMap!(StringOf, States) VarNames;
     string varPtrs;
     alias staticMap!(TypeStringOf, States) TypeNames;
     foreach (i, varName; VarNames)
     {
         if (varPtrs != null) { varPtrs ~= ", "; }
         if (stateArgs != null) { stateArgs ~= ", "; }
         varPtrs ~= varName;
         stateArgs ~= "ref " ~ TypeNames[i] ~ " " ~ varName;
         stateVars ~= TypeNames[i] ~ "* ___p_" ~ varName ~ "; ";
         stateProps ~= " property ref " ~ TypeNames[i] ~ " " ~ varName ~ 
"() { return *this.___p_" ~ varName ~ "; } ";
         setStateVars ~= "___tmp.___p_" ~ varName ~ " = &" ~ varName ~ "; ";
     }
     return "("
         ~ "delegate(" ~ stateArgs ~ ") { "
             ~ "static struct State { "
                 ~ stateVars ~ ""
                 ~ stateProps ~ ""
                 ~ "auto opCall" ~ argsAndBody
                 ~ ""
             ~ "} "
             ~ "State ___tmp; "
             ~ setStateVars
             ~ "return ___tmp; "
         ~"})(" ~ varPtrs ~ ")";
}
Aug 07 2011
parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Mon, 08 Aug 2011 04:51:19 +0200, Mehrdad <wfunction hotmail.com> wrote:

 I just made something I thought I'd share.

 It's great for those times when the compiler decides to randomly put a  
 closure on the heap.

 The usage is pretty simple:

      int x = 5;
      auto adder5 = mixin(closure!x(q{(int a) { return a + x; }}));
      assert(adder5(10) == 15);

 It returns a callable struct whose body is the given string; the  
 template parameters are the variables under closure (in this case, x).

 The generated code looks like (minus a little beautification on my part):

      (delegate(ref int x) {
          static struct State {
              int* px;
               property ref int x() { return *this.px; }
              auto opCall(int a) { return a + x; }
          }
          State tmp;
          tmp.px = &x;
          return tmp;
      })(x)

 So when you assign it to something, that something becomes a struct with  
 opCall overloaded. You can then take the address of opCall on the  
 struct, and you get a delegate.

 Thoughts?

You could use the 'scope' keyword, no? Upon perusal of the documentation, it seems this is nowhere mentioned, and a report may be in order. -- Simen
Aug 08 2011
next sibling parent %u <wfunction hotmail.com> writes:
 You could use the 'scope' keyword, no?

From what I've heard it's being deprecated/removed -- although I'd be glad to hear otherwise.
Aug 08 2011
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
 You could use the 'scope' keyword, no?

From what I've heard it's being deprecated/removed -- although I'd be glad to hear otherwise.

scope on function parameters is sticking around as are scoped statements. What's going around is scoped local variables which put a class on the stack. std.typecons.Scoped is replacing it. scoped delegates are sticking around though. - Jonathan M Davis
Aug 08 2011