foreach by value iteration

James Miller james at aatch.net
Sun Feb 26 15:20:11 PST 2012


On 27 February 2012 10:31, bearophile <bearophileHUGS at lycos.com> wrote:
> Peter Alexander:
>
>> Am I the only person that gets caught by this trap?
>
> I have being hit by this bug some times. I think this is a common enough bug in D code. But it's not easy to invent a way to solve it.
>
> ----------------
>
> Jonathan M Davis:
>
>> I really don't know how we could make it easier for you to avoid this error
>> without making it impossible to other, useful things. But your code works if
>> you use ref. You just have to remember to do that.
>
> To "just remember" to avoid the bug is an option, but programmers are not perfect.
>
> One possible solution is to generate a warning when a mutable struct copy is done. But I think this causes too many false positives (false alarms). In theory the compiler may avoid showing the warning if the copied mutable struct is _clearly_ not modified inside the loop body. This reduces the number of false positives, but I think not enough.
>
>
> Another possible solution is to require something in the foreach, like "ref" or "copy" (or "dup" instead of "copy"). Here I think it's clear that 'v' is a copy of the struct of 'vs' (maybe "copy" is not required if 'v' is not mutable):
>
> struct Vector {
>     void normalize() { this /= length; }
> }
> Vector[] vs;
> foreach (copy v; vs)
>     v.normalize();
>
>
> A mix of the two ideas is to generate the warning unless a "copy" or "ref" is present when there is a mutable copy. So "copy" is used just to silence the warning.
>
>
> Or maybe just an inlined comment /*copy*/ is needed to silence the warning/error:
>
> foreach (/*copy*/ v; vs)
>     v.normalize();
>
> Or a different foreach:
>
> foreach_copy (v; vs)
>     v.normalize();
>
> I think none of the ideas I've shown is good enough.
>
> Bye,
> bearophile

I'm with Jonathon, using `ref` is the best way, it is ridiculous to
think that the compiler should be able to figure out what's going on
in every case. After getting hit by it a couple times, then you'll
remember to use ref if you want to alter a copy.

By the way, its the same in other languages, you need to use
"reference" syntax to alter values in a loop. This is one case where
its not /immediately/ obvious what the problem is, "fixing" it would
inevitably cause other code to because "unituitive" so its pretty much
a lose-lose scenario. Even in D, we are going to have code that
compiles, runs, and doesn't do what you expect for some small reason.
At least in this case its the simple matter of adding `ref` to the
loop.

--
James Miller


More information about the Digitalmars-d mailing list