Thread overview
foreach and retro
Jul 02, 2012
Timon Gehr
Jul 02, 2012
Tobias Pankrath
Jul 02, 2012
Namespace
Jul 02, 2012
kenji hara
Jul 02, 2012
bearophile
Jul 02, 2012
Christophe Travert
July 02, 2012
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
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
> 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
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
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
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
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
"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
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
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 ... :-)