www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Interval foreach iteration variable

reply bearophile <bearophileHUGS lycos.com> writes:
This post is just about foreach performed on a range like 0..10, and not about
foreach in general (like forerach done on a iota(0,10). Note: the 0..10 syntax
may even become syntax sugar for iota(0,10) and the compiler may recognize
iota() calls and fully optimize it away).

This D2 program:

import std.stdio: write;
void main() {
    foreach (i; 0 .. 10) {
        write(i, " ");
        i += 1;
    }
}


Outputs:
0 2 4 6 8

But for a person accustomed to Python that looks strange, this is a similar
Python2 program:

from sys import stdout
for i in xrange(10):
    stdout.write("%d " % i)
    i += 1

It outputs:
0 1 2 3 4 5 6 7 8 9 


What's good in allowing the D foreach iteration variable when it loops on a
interval to be modified like that? I think it's a bit bug prone semantics.

foreach(a; b..c) semantics is not related to the for() semantics, foreach is
not present in C language, so D foreach is free to have any sane semantics it
desires.

So I think it's better the foreach interval iteration variable to be not
mutable.

There are important C style guides that warn against modifying the loop
variable inside the loop itself because it's not a very safe&clean thing to do
(and if necessary to set a flag that the for loop tests to break). So what I'm
suggesting here is not weird.

-------------------

I have recently added a related but different bug report:
http://d.puremagic.com/issues/show_bug.cgi?id=5306

Bye,
bearophile
Dec 01 2010
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday 01 December 2010 18:33:16 bearophile wrote:
 This post is just about foreach performed on a range like 0..10, and not
 about foreach in general (like forerach done on a iota(0,10). Note: the
 0..10 syntax may even become syntax sugar for iota(0,10) and the compiler
 may recognize iota() calls and fully optimize it away).
 
 This D2 program:
 
 import std.stdio: write;
 void main() {
     foreach (i; 0 .. 10) {
         write(i, " ");
         i += 1;
     }
 }
 
 
 Outputs:
 0 2 4 6 8
 
 But for a person accustomed to Python that looks strange, this is a similar
 Python2 program:
 
 from sys import stdout
 for i in xrange(10):
     stdout.write("%d " % i)
     i += 1
 
 It outputs:
 0 1 2 3 4 5 6 7 8 9
 
 
 What's good in allowing the D foreach iteration variable when it loops on a
 interval to be modified like that? I think it's a bit bug prone semantics.
 
 foreach(a; b..c) semantics is not related to the for() semantics, foreach
 is not present in C language, so D foreach is free to have any sane
 semantics it desires.
 
 So I think it's better the foreach interval iteration variable to be not
 mutable.
 
 There are important C style guides that warn against modifying the loop
 variable inside the loop itself because it's not a very safe&clean thing
 to do (and if necessary to set a flag that the for loop tests to break).
 So what I'm suggesting here is not weird.
 
 -------------------
 
 I have recently added a related but different bug report:
 http://d.puremagic.com/issues/show_bug.cgi?id=5306

What I would have thought would be the case would be that if the index variable was ref, then altering changed which index you got on the next iteration, but that if it wasn't ref, changing it would do nothing - just how it works with the element variable. I definitely agree that the fact that changing the index variable when it's not marked as ref is inconsistent and undesirable behavior, but I don't agree that it should not be possible to do it by ref as your post implies. - Jonathan M Davis
Dec 01 2010