Thread overview
Copying a variable state in a delegate literal definition
Sep 02, 2011
Andrej Mitrovic
Sep 02, 2011
David Nadlinger
Sep 02, 2011
Andrej Mitrovic
Sep 03, 2011
Daniel Murphy
September 02, 2011
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?
September 02, 2011
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
September 02, 2011
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
September 02, 2011
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!
September 03, 2011
"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);