www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - No index for cycle ranges

reply Andrej Mitrovic <none none.none> writes:
import std.range;

void main()
{
    auto arr = [1, 2, 3, 4, 5, 6, 7, 8];
    auto foo = cycle(arr);
    
    // nope
    foreach (int index, int val; foo)
    {
    }    
    
    // nope
    foreach (int index, int val; take(foo, 5))
    {
    }
    
    // ok
    foreach (int index, int val; take(arr, 5))
    {
    }    
}

Is this because cycle is an infinite range, and index might overflow? I could
understand that. But I think if I use take() then there should be no problem
with overflows. It still doesn't work though.
Jun 02 2011
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Andrej Mitrovic:

 Is this because cycle is an infinite range, and index might overflow?
The cause is different: cycle is a range, and they don't define an counter variable. With opApply sometimes you define the counter too. The compiler doesn't create a counter variable for free. Bye, bearophile
Jun 02 2011
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 02 Jun 2011 14:17:26 -0400, Andrej Mitrovic <none none.none> wrote:

 import std.range;

 void main()
 {
     auto arr = [1, 2, 3, 4, 5, 6, 7, 8];
     auto foo = cycle(arr);
    // nope
     foreach (int index, int val; foo)
     {
     }
    // nope
     foreach (int index, int val; take(foo, 5))
     {
     }
    // ok
     foreach (int index, int val; take(arr, 5))
     {
     }
 }

 Is this because cycle is an infinite range, and index might overflow? I  
 could understand that. But I think if I use take() then there should be  
 no problem with overflows. It still doesn't work though.
As bearophile says, there is no standard for the index portion of a range (except for slices, which also happen to be ranges) during foreach. The reason take(arr, 5) works is because it translates to arr[0..5] which is a slice. -Steve
Jun 02 2011
parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Well actually all I wanted was a counter variable. I can put the thing
in a for loop or while loop, but I thought that a counter variable is
something that the compiler can always add without too much thinking.

I guess things aren't so simple.
Jun 02 2011
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 02 Jun 2011 17:38:38 -0400, Andrej Mitrovic  
<andrej.mitrovich gmail.com> wrote:

 Well actually all I wanted was a counter variable. I can put the thing
 in a for loop or while loop, but I thought that a counter variable is
 something that the compiler can always add without too much thinking.

 I guess things aren't so simple.
In fact, if indexes for ranges were implemented during foreach, it would *have* to be this way. An explanation: Note that foreach(x; range) translates to: auto _r = range; for(; !_r.empty; _r.popNext()) { auto x = _r.front; ... } So think about this for a second, if you wanted to add an index variable, what is the index of _r.front()? In the case of simple arrays, it's *always* 0! So the index would have to be tracked by the loop, not by the range. But we'd also need a way to override this. For instance, a range on an associative array, the index is not a sequential integer series starting at 0. So I'm not sure how this would be solved, but it's definitely complicated. Note that opApply solves this beautifully, since opApply has it's own temporary scope where you can track anything you want. -Steve
Jun 02 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Steven Schveighoffer:

 So I'm not sure how this would be solved, but it's definitely complicated.
To solve this problem Python uses the enumerate function:
 for c in "abc":
... print c ... a b c
 for i,c in enumerate("abc"):
... print i, c ... 0 a 1 b 2 c In D it's easy to create something similar to enumerate, that yields tuple(index,item). But in D there is no syntax sugar for tuple unpacking yet, so here the index management becomes less nice. I suggest to add enumerate to std.range, see: http://d.puremagic.com/issues/show_bug.cgi?id=5550 Bye, bearophile
Jun 02 2011
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 02 Jun 2011 17:38:38 -0400, Andrej Mitrovic  
<andrej.mitrovich gmail.com> wrote:

 Well actually all I wanted was a counter variable. I can put the thing
 in a for loop or while loop, but I thought that a counter variable is
 something that the compiler can always add without too much thinking.
Also, BTW, you can still do this with a foreach loop: size_t idx = ~0; //hacky, I know. foreach(x; range) { ++idx; ... } -Steve
Jun 02 2011
parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 6/2/11, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 On Thu, 02 Jun 2011 17:38:38 -0400, Andrej Mitrovic
 <andrej.mitrovich gmail.com> wrote:

 Well actually all I wanted was a counter variable. I can put the thing
 in a for loop or while loop, but I thought that a counter variable is
 something that the compiler can always add without too much thinking.
Also, BTW, you can still do this with a foreach loop: size_t idx = ~0; //hacky, I know. foreach(x; range) { ++idx; ... } -Steve
Heh, I thought I'd never see a use-case for an overflow. Btw., did ya know you can cram more expressions before the range? size_t idx; foreach(x; idx = ~0, [1, 2, 3]) { writeln(++idx); }
Jun 02 2011
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 02 Jun 2011 18:01:21 -0400, Andrej Mitrovic  
<andrej.mitrovich gmail.com> wrote:

 On 6/2/11, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 On Thu, 02 Jun 2011 17:38:38 -0400, Andrej Mitrovic
 <andrej.mitrovich gmail.com> wrote:

 Well actually all I wanted was a counter variable. I can put the thing
 in a for loop or while loop, but I thought that a counter variable is
 something that the compiler can always add without too much thinking.
Also, BTW, you can still do this with a foreach loop: size_t idx = ~0; //hacky, I know. foreach(x; range) { ++idx; ... } -Steve
Heh, I thought I'd never see a use-case for an overflow. Btw., did ya know you can cram more expressions before the range? size_t idx; foreach(x; idx = ~0, [1, 2, 3]) { writeln(++idx); }
That is so... so evil... I mean the plethora of commas, *shudder*. :) -Steve
Jun 02 2011