www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Copying a variable state in a delegate literal definition

reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
So I have this code right here (semi-pseudocode) inside a "MenuBar" widget:

void showMenu(index menuIndex) { }
void appendMenuButton()
{
    static size_t menuIndex;
    // create menu button, and then:
    button.connect!(Signal.MouseClick) = { this.showMenu(menuIndex); };
    menuIndex++;
}

button is a newly constructed widget object, Signal is just an enum.
Inside of my Widget class I have this:

    void delegate()[] clickHandlers;

     property void connect(Signal signal)(void delegate() dg)
    {
        static if (signal == Signal.MouseClick)
            clickHandlers ~= dg;
        else
            // ...
    }

    void onClicked()
    {
        foreach (handler; clickHandlers)
        {
            handler();
        }
    }

So far so good. This works except for the following quirk:

button.connect!(Signal.MouseClick) = { this.showMenu(menuIndex); };

Inside this lambda menuIndex is accessed through that frame pointer
when the lambda is called. But I actually want a *copy* of menuIndex
at the definition site. Because as I call appendMenuButton() numerous
times, menuIndex is increased, so if I do this:

menu.appendMenuButton();
menu.appendMenuButton();

 { this.showMenu(menuIndex); }; becomes:
 { this.showMenu(2); };

when it is called. I can't use a function literal instead of a
delegate literal because I want to have access to "this.showMenu", but
I want a copy of menuIndex. I've tried this:

{ size_t index = menuIndex; writeln(index); }

However that doesn't copy the state either, it initializes index with
the menuIndex in the frame pointer when the literal is called.

So how can I selectively copy the state of some variables at the site
of the definition of a delegate literal?
Sep 02 2011
next sibling parent David Nadlinger <see klickverbot.at> writes:
On 9/2/11 8:29 PM, Andrej Mitrovic wrote:
 So how can I selectively copy the state of some variables at the site
 of the definition of a delegate literal?

You can try introducing a new frame using a immediately executed delegate literal: button.connect!(Signal.MouseClick) = { auto index = menuIndex; return { this.showMenu(index); }; }(); David
Sep 02 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 02 Sep 2011 14:29:18 -0400, Andrej Mitrovic  
<andrej.mitrovich gmail.com> wrote:

 So I have this code right here (semi-pseudocode) inside a "MenuBar"  
 widget:

 void showMenu(index menuIndex) { }
 void appendMenuButton()
 {
     static size_t menuIndex;
     // create menu button, and then:
     button.connect!(Signal.MouseClick) = { this.showMenu(menuIndex); };
     menuIndex++;
 }

 button is a newly constructed widget object, Signal is just an enum.
 Inside of my Widget class I have this:

     void delegate()[] clickHandlers;

      property void connect(Signal signal)(void delegate() dg)
     {
         static if (signal == Signal.MouseClick)
             clickHandlers ~= dg;
         else
             // ...
     }

     void onClicked()
     {
         foreach (handler; clickHandlers)
         {
             handler();
         }
     }

 So far so good. This works except for the following quirk:

 button.connect!(Signal.MouseClick) = { this.showMenu(menuIndex); };

 Inside this lambda menuIndex is accessed through that frame pointer
 when the lambda is called. But I actually want a *copy* of menuIndex
 at the definition site. Because as I call appendMenuButton() numerous
 times, menuIndex is increased, so if I do this:

 menu.appendMenuButton();
 menu.appendMenuButton();

  { this.showMenu(menuIndex); }; becomes:
  { this.showMenu(2); };

 when it is called. I can't use a function literal instead of a
 delegate literal because I want to have access to "this.showMenu", but
 I want a copy of menuIndex. I've tried this:

 { size_t index = menuIndex; writeln(index); }

 However that doesn't copy the state either, it initializes index with
 the menuIndex in the frame pointer when the literal is called.

 So how can I selectively copy the state of some variables at the site
 of the definition of a delegate literal?

Am I missing something, or is it this simple? void appendMenuButton() { static size_t menuIndex; auto frameIndex = menuIndex++; button.connect!(Signal.MouseClick) = { this.showMenu(frameIndex); }; } -Steve
Sep 02 2011
prev sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/2/11, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 Am I missing something, or is it this simple?

 void appendMenuButton()
 {
     static size_t menuIndex;
     auto frameIndex = menuIndex++;
     button.connect!(Signal.MouseClick) = { this.showMenu(frameIndex); };
 }

 -Steve

Actually It *is* that simple. Which is odd because I swear I've tried it once but it didn't work, and now it works again. Something has to be messing with the compiler or my brain!
Sep 02 2011
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message 
news:mailman.2651.1315000369.14074.digitalmars-d-learn puremagic.com...
 On 9/2/11, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 Am I missing something, or is it this simple?

 void appendMenuButton()
 {
     static size_t menuIndex;
     auto frameIndex = menuIndex++;
     button.connect!(Signal.MouseClick) = { this.showMenu(frameIndex); };
 }

 -Steve

Actually It *is* that simple. Which is odd because I swear I've tried it once but it didn't work, and now it works again. Something has to be messing with the compiler or my brain!

It won't work when loops are involved. In that case I usually use: foreach(i; ...) (int i){ something = { delegate that uses i like a constant }; }(i);
Sep 02 2011