Can we fix this?

deadalnix deadalnix at gmail.com
Thu Sep 30 00:59:26 UTC 2021


On Wednesday, 29 September 2021 at 16:47:23 UTC, Steven 
Schveighoffer wrote:
> What we need is a syntax to specify which values are captured 
> and which variables are referenced.
>
> What I normally do if I need something like this is:
>
> ```d
> foreach(int i; [1, 2, 3]) {
>    dgList ~= (b) { return {writeln(b);};} (i + 2);
>    // or less error prone:
>    dgList ~= (i) { return {writeln(i + 2);};} (i);
> }
>

This is where things go off rails. We don't need any new syntax. 
We need to stop adding a new gizmo every time something is not 
doing the right thing. The ed result is that the original thing 
still don't do the right thing and the gizmo also doesn't do the 
right thing because it has been though to solve a specific edge 
case.

Now, foreach is a high level construct, and just get the same 
semantic as what it lowers into. Let's use while loops.

```d
int i = 1;
while (i < 4) {
    dgList ~= { writeln(i + 2); }; // still outputs 5 5 5
}
```

Now, this is expected isn't it? There is one and only one i 
variable. But let's change things a bit.

```d
int i = 1;
while (i < 4) {
    int n = i + 2;
    dgList ~= { writeln(n); }; // still outputs 5 5 5
}
```

Now this is wrong. A new n variable is created at each loop 
iteration, this isn't the same n. It's easy to convince oneself 
that this is the case: n can be made immutable and the code still 
compiles, which is evidence that the semantic is that each loop 
iteration has a new n variable.

So either we create a new closure for each loop iteration (if a 
variable locale to the loop is captured), or making n immutable 
must be rejected, because either n in one variable across all 
iterations, and it is mutated, or it is not, but it can't be both.

For completeness, it must be noted that the former tends to b 
what's expected, this is what C# is doing for instance.


More information about the Digitalmars-d mailing list