Another foreach idea.

Kirk McDonald kirklin.mcdonald at gmail.com
Wed Jun 7 21:40:45 PDT 2006


Dave wrote:
> 
> Instead of:
> 
> for(int i = 1_000; i < 1_000_000; i++) {}
> 
> How about:
> 
> foreach(idx; 1_000 .. 1_000_000)
> {
>     // 1_000 to 999_999 or 1_000 to 1_000_000?
>     // type inferred 'idx' would be an int or long
>     //  depending on 32 bit or 64 bit hardware
> }
> 
> or simply:
> 
> size_t x = 1_000_000;
> 
> foreach(idx; x)
> {
>     // 0 to 999_999 or 1 to 1_000_000?
>     // type inferred 'idx' is size_t
> }
> 
> The rational would be not only for brevity but also the reasons given 
> here: http://digitalmars.com/d/faq.html#foreach
> 
> I can see the problems already - 0 or 1 based? 0 based to be consistent 
> with how many for loops are written now and with array indexing (even 
> though presumably you'd then use foreach with the array itself)? Or 1 
> based because then it would be WYSIWYG.
> 
> - Dave

This is very much like Python's behavior. In that language, there isn't 
a "for" loop as such, only a "foreach" loop. To loop a counter from 0 to 
9, you'd write:

for i in range(10):
     print i

Where "range" is a function that returns a list containing a range of 
integers, with a footprint like:

range(start=0, end, step=1)

(Python allows default values in places that D does not.) There is also 
an xrange function, which returns a generator rather than a whole list, 
which can be more useful for large ranges.

To loop from 10 to 99, you'd write:

for i in range(10, 100):
     print i

In short, all you need is a "range" function that returns an array of 
integers, or (alternately) a generator... something like this:

private import std.stdio;

class range {
protected:
     int m_start, m_end;
     int m_step = 1;
public:
     // Can't just specify (end, step), but there's nothing
     // to be done for that.
     this(int end) {
         m_end = end;
     }
     this(int start, int end) {
         m_start = start;
         this(end);
     }
     this(int start, int end, int step) {
         m_step = step;
         this(start, end);
     }

     // Convenience functions
     static range opCall(int end) {
         return new range(end);
     }
     static range opCall(int start, int end) {
         return new range(start, end);
     }
     static range opCall(int start, int end, int step) {
         return new range(start, end, step);
     }

     // Compares whether i has reached the end
     private bool cmp(int i) {
         if (m_step > 0 && i < m_end) return true;
         else if (m_step < 0 && i > m_end) return true;
         else return false;
     }

     int opApply(int delegate(inout int) dg) {
         int result = 0;
         for (int i=m_start; this.cmp(i); i+=m_step) {
             result = dg(i);
             if (result) break;
         }
         return result;
     }
}

void main() {
     foreach(i; range(10)) {
         writefln("%s", i);
     }
     foreach(j; range(10, 20)) {
         writefln("%s", j);
     }
     foreach(k; range(0, 10, 2)) {
         writefln("%s", k);
     }
}

Though honestly, a regular for loop isn't much of a burden.

-Kirk McDonald



More information about the Digitalmars-d mailing list