Search code examples
foreachranged

How to make Range work with foreach statement


I have the following range:

struct Range {
  uint data;

  @property{
    bool empty() { return false; }
    uint front() { return data; }
    void popFront() { data = data * 2 + 1; }
  }
}

Trying to use it, foreach(c; Rnage()){ /*...*/ } works, but with foreach(i, c; Range()){ /*...*/ } I get:

Error: cannot infer argument types

I need the i just like in something like foreach(i, v; [1,2,3,4]){ }.


Solution

  • Ranges do not support the syntax

    foreach(i, c; range)
    

    While it seems obvious that that should work in the simple case, what that index should even be depends on the type of range and doesn't always make sense. So, no counter for the index is provided automatically by foreach, and a range has no way of providing one.

    However, thanks to tuple unpacking with foreach, you can do it by using std.range.sequence std.range.zip with your range:

    foreach (i, e; zip(sequence!"n"(), range))
    {
    }
    

    By the way, you shouldn't mark popFront with @property. It doesn't make any sense. popFront takes no arguments and returns no value. It does not act like a variable at all. And the point of properties is to have functions which act like variables. If/when -property's implementation is fully sorted out and it becomes the normal behavior (it's rather buggy at the moment, which is part of why it's a separate switch for the moment), popFront would not be usable as you defined it.