View mode: basic / threaded / horizontal-split · Log in · Help
July 02, 2012
foreach and retro
Hello all,

A problem with the retro function from std.range -- although it apparently 
operates on a bidirectional range, it fails when used with foreach requesting 
both value and index.  Running this code:

////////////////////////////////////////////////
import std.range, std.stdio;

void main()
{
      double[] a = [ 0, 1, 2, 3, 4, 5 ];

      foreach(i, x; retro(a))
            writeln(i, "\t", x);
}
////////////////////////////////////////////////

... results in an error: "cannot infer argument types".

Is there any reason why this should be so, or is it (as it seems to me) just a bug?

Thanks & best wishes,

    -- Joe
July 02, 2012
Re: foreach and retro
On 07/02/2012 05:36 PM, Joseph Rushton Wakeling wrote:
> Hello all,
>
> A problem with the retro function from std.range -- although it
> apparently operates on a bidirectional range, it fails when used with
> foreach requesting both value and index.  Running this code:
>
> ////////////////////////////////////////////////
> import std.range, std.stdio;
>
> void main()
> {
>        double[] a = [ 0, 1, 2, 3, 4, 5 ];
>
>        foreach(i, x; retro(a))
>              writeln(i, "\t", x);
> }
> ////////////////////////////////////////////////
>
> ... results in an error: "cannot infer argument types".
>
> Is there any reason why this should be so, or is it (as it seems to me)
> just a bug?
>
> Thanks & best wishes,
>
>      -- Joe

What would be your expected output?
July 02, 2012
Re: foreach and retro
> What would be your expected output?

 From the inner to the outer expression:

First the range is reversed and then the elements of this range
are enumerated.
July 02, 2012
Re: foreach and retro
Joseph Rushton Wakeling:

>       double[] a = [ 0, 1, 2, 3, 4, 5 ];
>
>       foreach(i, x; retro(a))
>             writeln(i, "\t", x);

It's not a bug, it's caused by how ranges like retro work. retro 
yields a single item. In D you can't overload on return values, 
so foreach can't try to call a second retro.front overload that 
yields an (index,item) tuple (that later foreach is able to 
unpack on the fly) instead of the retro.front that just yields 
the item.

To solve that problem this is what I have suggested to add to 
Phobos:
http://d.puremagic.com/issues/show_bug.cgi?id=5550

Bye,
bearophile
July 02, 2012
Re: foreach and retro
On 02/07/12 17:48, Timon Gehr wrote:
> What would be your expected output?

I'd expect to see

0     5
1     4
2     3
3     2
4     1
5     0

i.e. as if I was foreach-ing over an array with the same values in inverted order.
July 02, 2012
Re: foreach and retro
On Monday, 2 July 2012 at 16:49:06 UTC, Joseph Rushton Wakeling 
wrote:
> On 02/07/12 17:48, Timon Gehr wrote:
>> What would be your expected output?
>
> I'd expect to see
>
> 0     5
> 1     4
> 2     3
> 3     2
> 4     1
> 5     0
>
> i.e. as if I was foreach-ing over an array with the same values 
> in inverted order.

Use the .array() property:

auto Range(alias func, Args...)(Args args) {
	return func(args).array();
}

void main() {}
	double[] ad = [ 0, 1, 2, 3, 4, 5 ];

	foreach(index, x; Range!(retro)(ad)) {
		writeln(index, "\t", x);
	}
}
July 02, 2012
Re: foreach and retro
D does not provide index for the range iteration.
Instead, you can create 'zipped' range.

void main() {
     auto intr = sequence!"n"();  // 0, 1, 2, ...
     double[] a = [ 0, 1, 2, 3, 4, 5 ];
     foreach(i, x; zip(intr, retro(a)))
           writeln(i, "\t", x);
}

zip(intr, retro(a)) is a range of Tuple!(size_t, double), and foreach
automatically expand the tow fields of zip front into i and x like
follows.

     foreach(__e; zip(intr, retro(a))) {
           auto i = __elem[0], x = __elem[1];   // inserted by the compiler
           writeln(i, "\t", x);
     }

After all, you can get 'index' for range iteration.

Kenji Hara

2012/7/3 Joseph Rushton Wakeling <joseph.wakeling@webdrake.net>:
> On 02/07/12 17:48, Timon Gehr wrote:
>>
>> What would be your expected output?
>
>
> I'd expect to see
>
> 0     5
> 1     4
> 2     3
> 3     2
> 4     1
> 5     0
>
> i.e. as if I was foreach-ing over an array with the same values in inverted
> order.
July 02, 2012
Re: foreach and retro
"bearophile" , dans le message (digitalmars.D:171013), a écrit :
> It's not a bug, it's caused by how ranges like retro work. retro 
> yields a single item. In D you can't overload on return values, 

But you can overload OpApply.

-- 
Christophe
July 04, 2012
Re: foreach and retro
On 02/07/12 18:43, bearophile wrote:
> It's not a bug, it's caused by how ranges like retro work. retro yields a single
> item. In D you can't overload on return values, so foreach can't try to call a
> second retro.front overload that yields an (index,item) tuple (that later
> foreach is able to unpack on the fly) instead of the retro.front that just
> yields the item.

Ahh, OK.  Clear, just a little surprising.

> To solve that problem this is what I have suggested to add to Phobos:
> http://d.puremagic.com/issues/show_bug.cgi?id=5550

Looks like a nice idea!

The reason I was interested was because of a case where a foreach_reverse was 
called for across an array, but where it was useful to flip the indices as well.
July 04, 2012
Re: foreach and retro
On 02/07/12 18:57, kenji hara wrote:
> D does not provide index for the range iteration.
> Instead, you can create 'zipped' range.

Oh, cool.  That's a nice feature that I can think of other uses for ... :-)
Top | Discussion index | About this forum | D home