How to avoid variable capturing in `foreach` loop with lambdas?

H. S. Teoh hsteoh at qfbox.info
Thu Jan 5 17:36:55 UTC 2023


On Thu, Jan 05, 2023 at 11:55:33AM +0000, thebluepandabear via Digitalmars-d-learn 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);
> }
> ```

This is a classic D trap: the loop variable is only allocated once, and
the closure captures the single location where the loop variable
resides, thus every delegate from every loop iteration will see the same
value when they are run later, i.e., the last value of the loop index.
Do this instead:

```D
foreach (BoardSize boardSize; arr) {
    Button button = new Button();
    button.text = format("%sx%s", boardSize[0], boardSize[1]);
    BoardSize size = boardSize; // force separate capture
    button.onButtonClick = {
        eventHandler.settingsWindow_onBoardSizeButtonClick(size);
    };
    button.onButtonClick();
    _boardSizeRow.addChild(button);
}
```

This is arguably a language bug (I can't imagine any sane use case where
somebody would actually want the current semantics).  But we have not be
successful in convincing Walter about this...


T

-- 
Don't throw out the baby with the bathwater. Use your hands...


More information about the Digitalmars-d-learn mailing list