DMD Bug or not? foreach over struct range

Jonathan M Davis jmdavisProg at gmx.com
Wed May 16 00:40:54 PDT 2012


On Wednesday, May 16, 2012 09:24:23 Era Scarecrow wrote:
> On Wednesday, 16 May 2012 at 07:04:09 UTC, Jonathan M Davis wrote:
> > that assertion would pass, but it doesn't, and it shouldn't. If
> > your range was a reference type (e.g. if it were a class or it
> > was like the ranges in std.stdio which deal with I/O), then
> > using it with foreach would consume it, but that won't happen
> > with a value type range.
> 
>   Then perhaps I'm missing something. Some time ago (6 months?) I
> submitted a similar example of this to walter; a little prime
> walking range-like struct that acts like a range. It may contain
> an AA, but otherwise basic structure isn't far from his...
> 
>   Could you explain why mine works and his doesn't? (Extras taken
> out proving ever number is a prime)
> 
> ---
> import std.stdio;
> 
> struct prime_walk {
>    int map[int];
>    int position = 2;
>    int cap = int.max;
> 
>    int front() {
>      return position;
>    }
> 
>    void popFront() {
>      //where the real work is done.
> 
>      if ((position & 1) == 0) {
>        position++;
>      } else if (position >= cap) {
>        throw new Exception("Out of bounds!");
>      } else {
>        int div = position;
>        int p2 = position * 3;
> 
>        //current spot IS a prime. So...
>        if (p2 < cap)
>          map[p2] = div;
> 
>        position += 2;
> 
>        //identify marked spot, if so we loop again.
>        while (position in map) {
>          div = map[position];
>          map.remove(position);
>          p2 = position;
>          do
>            p2 += div * 2;
>          while (p2 in map);
> 
>          position += 2;
>          if (p2 <= cap)  //skip out, no need to save larger than
> needed values.
>            map[p2] = div;
>        }
>      }
>    }
> 
>    bool empty() {
>      return position >= cap;
>    }
> }
> 
> void main() {
>    prime_walk pw;
>    pw.cap = 100;
>    foreach(i; pw)
>      writeln(i);
> }

I'm not quite sure what yours is doing, but yours isn't empty after the call 
to foreach any more than Nick's is. The issue with Nick's is that he's using 
the original range _inside_ the loop and not seeing the changes. Your loop 
isn't referencing the original range. It just uses its copy. If you did

void main()
{
    prime_walk pw;
    pw.cap = 100;
    foreach(i; pw)
        writefln("%s %s", i, pw.position);
}

You'd see that pw.postion is always printed as 2, just like Nick's foo.val 
always prints as 0.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list