On Thursday, 5 January 2023 at 11:55:33 UTC, thebluepandabear wrote:
```D
foreach (BoardSize boardSize; arr) {
    Button button = new Button();
    button.text = format("%sx%s", boardSize[0], boardSize[1]);
    button.onButtonClick = {
eventHandler.settingsWindow_onBoardSizeButtonClick(boardSize);
    };
    button.onButtonClick();
    _boardSizeRow.addChild(button);
}
```

Running this code, I had expected that everything would work fine. Unfortunately upon running the code, tapping each of the buttons returned only the largest `boardSize` value, the one which is gets iterated last.

The problem is twofold:

1. Closures in D capture their environment by reference.
2. D (incorrectly, in my opinion) considers loop-local variables to have the same identity across each iteration of the loop within a single function call.

So, `boardSize` in your event handler is a reference to a single variable whose value is overwritten on each iteration of the loop. As the event handlers are (I presume) never called until after the loop has terminated, the only value they will ever see is whichever was set by the final iteration of the loop in that function call.

There are at least two possible solutions:

1. Use a `struct` to explicitly capture `boardSize` by value, instead of by reference:
```D
static struct ClickHandler {
// If eventHandler is not a global variable of some sort, add another field for it:
    BoardSize iteration_boardSize;
    this(BoardSize iteration_boardSize) {
        this.iteration_boardSize = iteration_boardSize;
    }

    void opCall() {
eventHandler.settingsWindow_onBoardSizeButtonClick(iteration_boardSize);
    }
}

foreach (BoardSize loop_boardSize; arr) {
    Button button = new Button();
button.text = format("%sx%s", loop_boardSize[0], loop_boardSize[1]); button.onButtonClick = &(new ClickHandler(loop_boardSize)).opCall;
    button.onButtonClick();
    _boardSizeRow.addChild(button);
}
```

2. Use a nested function call with a `boardSize` parameter to create a copy of `boardSize` with a unique identity on each iteration of the loop:
```D
foreach (BoardSize loop_boardSize; arr) {
    Button button = new Button();
button.text = format("%sx%s", loop_boardSize[0], loop_boardSize[1]);
    button.onButtonClick = (BoardSize iteration_boardSize) {
        return {
eventHandler.settingsWindow_onBoardSizeButtonClick(iteration_boardSize);
        };
    }(loop_boardSize);
    button.onButtonClick();
    _boardSizeRow.addChild(button);
}
```

These two solutions should compile to approximately the same runtime code, with optimizations enabled. So, it's really down to personal preference; the former is more explicit about what the computer is to do, while the latter is more concise.

Reply via email to