Bug 6214 – Don't influence foreach iteration on range
Status
RESOLVED
Resolution
DUPLICATE
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2011-06-26T01:30:00Z
Last change time
2012-11-02T21:12:30Z
Assigned to
nobody
Creator
bearophile_hugs
Comments
Comment #0 by bearophile_hugs — 2011-06-26T01:30:18Z
This is a little Python 2.6 program:
for i in xrange(10):
i += 1
print i,
Its output shows that you are allowed to modify the iteration variable (contents of the iteration name), but the iteration goes on with no change:
1 2 3 4 5 6 7 8 9 10
Similar code in D using foreach shows a different story:
import std.stdio;
void main() {
foreach (i; 0 .. 10) {
i += 1;
write(i, " ");
}
}
The output:
1 3 5 7 9
In my opinion this is a bit bug-prone because in real code there is some risk of modifying the iteration variable "i" by mistake. (Note: here I am not talking about D for() loops. They are OK, their semantics is transparent enough. foreach() loops are less transparent and they *look* higher level than for() loops). I'd like the iteration variable to act as being a copy of the true loop variable as in Python. If this is a bit bad for foreach performance, then I'd like the compiler to forbid the mutation of the foreach iteration variable inside the foreach body.
Currently you can't solve the problem adding a const(int) to the iteration variable:
import std.stdio;
void main() {
foreach (const(int) i; 0 .. 10) { // line 3
write(i, " ");
}
}
DMD 2.053 gives:
test.d(3): Error: variable test.main.i cannot modify const
----------------------
One answer to Caligo:
> This:
>
> foreach(i; 0..10){
> i += 1;
> write(i, " ");
> }
>
> is the same as this:
>
> for(int i = 0; i < 10; ++i){
> i += 1;
> write(i, " ");
> }
The problem is this equivalence is hidden. foreach() loops look higher level than for loops. So programmers expect this higher level look to be associated with a higher level semantics too. This is why I think currently they are a bit bug-prone. Modifying the loop variable of a foreach loop is code smell, if I see it in code I fix it in some way, using a copy of the loop variable, or I replace the foreach loop with a for loop. So I'd like the compiler to "ignore" or probably better refuse such modifications to the foreach loop variable, if possible.
-------------------
This idea has generate a long thread. Most people in the thread seem to generally agree:
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=138630http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=138852
Maybe even Andrei, but I think Walter has not expressed his opinion yet:
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=138718
-------------------
The idea is to align the semantics of foreach(x;a..b) to the semantics of foreach(x;iota(a,b)), because in my opinion a range like 5..10 has to be seen as the literal for an immutable thing, just like a single number, so you are not allowed to skip some of its items. On this see also bug 4603
Some people suggest to allow the mutation of the range iteration variable on request, adding a "ref":
foreach(ref i; 0..10)
-------------------
See also bug 5255
Comment #1 by bearophile_hugs — 2011-06-26T02:07:01Z
This is an older enhancement requst, bug 5306
Comment #2 by k.hara.pg — 2012-11-02T21:12:30Z
(In reply to comment #0)
> import std.stdio;
> void main() {
> foreach (i; 0 .. 10) {
> i += 1;
> write(i, " ");
> }
> }
>
> The output:
> 1 3 5 7 9
>
> In my opinion this is a bit bug-prone because in real code there is some risk
> of modifying the iteration variable "i" by mistake. (Note: here I am not
> talking about D for() loops. They are OK, their semantics is transparent
> enough. foreach() loops are less transparent and they *look* higher level than
> for() loops). I'd like the iteration variable to act as being a copy of the
> true loop variable as in Python. If this is a bit bad for foreach performance,
> then I'd like the compiler to forbid the mutation of the foreach iteration
> variable inside the foreach body.
This is now progressing by fixing bug 6652. So I'll mark this as a dup of it.
> Currently you can't solve the problem adding a const(int) to the iteration
> variable:
>
> import std.stdio;
> void main() {
> foreach (const(int) i; 0 .. 10) { // line 3
> write(i, " ");
> }
> }
>
> DMD 2.053 gives:
> test.d(3): Error: variable test.main.i cannot modify const
This is a dup of bug 4090, and it is mostly fixed in 2.061head.
*** This issue has been marked as a duplicate of issue 6652 ***