www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Unexpected behaviour of foreach statement

reply Arredondo <arm.plus gmail.com> writes:
Hi,

The following works as expected:

auto range = [1, 2, 3, 4, 5];
foreach (i, el; range) {
	writeln(i, ": ", el);
}

but this slight modification doesn't:

auto range = iota(5);
foreach (i, el; range) {
	writeln(i, ": ", el);
}

DMD 2.078.3 says:
Error: cannot infer argument types, expected 1 argument, not 2

The error message is not helpful either, because indicating the 
types, as in:

foreach (int i, int el; range) { ... }

throws the same error.
What's going on here?

Arredondo
Mar 02 2018
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 02/03/2018 11:21 PM, Arredondo wrote:
 Hi,
 
 The following works as expected:
 
 auto range = [1, 2, 3, 4, 5];
 foreach (i, el; range) {
      writeln(i, ": ", el);
 }
s/range/array/ Arrays have a different foreach syntax than ranges do.
Mar 02 2018
prev sibling next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Friday, 2 March 2018 at 10:21:39 UTC, Arredondo wrote:
 Hi,

 The following works as expected:

 auto range = [1, 2, 3, 4, 5];
 foreach (i, el; range) {
 	writeln(i, ": ", el);
 }

 but this slight modification doesn't:

 auto range = iota(5);
 foreach (i, el; range) {
 	writeln(i, ": ", el);
 }

 DMD 2.078.3 says:
 Error: cannot infer argument types, expected 1 argument, not 2

 The error message is not helpful either, because indicating the 
 types, as in:

 foreach (int i, int el; range) { ... }

 throws the same error.
 What's going on here?

 Arredondo
try https://dlang.org/phobos/std_range.html#enumerate
 foreach (i, el; enumerate(range)) {
 	writeln(i, ": ", el);
 }
Mar 02 2018
parent Arredondo <arm.plus gmail.com> writes:
On Friday, 2 March 2018 at 10:27:27 UTC, Nicholas Wilson wrote:
 try
 https://dlang.org/phobos/std_range.html#enumerate
This worked. Thank you!
Mar 02 2018
prev sibling next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, March 02, 2018 10:21:39 Arredondo via Digitalmars-d-learn wrote:
 Hi,

 The following works as expected:

 auto range = [1, 2, 3, 4, 5];
 foreach (i, el; range) {
   writeln(i, ": ", el);
 }

 but this slight modification doesn't:

 auto range = iota(5);
 foreach (i, el; range) {
   writeln(i, ": ", el);
 }

 DMD 2.078.3 says:
 Error: cannot infer argument types, expected 1 argument, not 2

 The error message is not helpful either, because indicating the
 types, as in:

 foreach (int i, int el; range) { ... }

 throws the same error.
 What's going on here?
foreach does not support indices for ranges, only arrays. When you have foreach(e; range) it gets lowered to foreach(auto __range = range; !__range.empty; __range.popFront()) { auto e = __range.front; } There are no indices involved there, and if a range isn't a random-access range, it doesn't support any kind of indices anyway. The compiler would have to add a variable to count the elements, and it doesn't support that. Your best options are either lockstep with iota or enumerate: https://dlang.org/phobos/std_range.html#lockstep https://dlang.org/phobos/std_range.html#enumerate - Jonathan M Davis
Mar 02 2018
parent Arredondo <arm.plus gmail.com> writes:
On Friday, 2 March 2018 at 10:32:08 UTC, Jonathan M Davis wrote:
 foreach does not support indices for ranges, only arrays. When 
 you have

 foreach(e; range)

 it gets lowered to

 foreach(auto __range = range; !__range.empty; 
 __range.popFront())
 {
     auto e = __range.front;
 }

 There are no indices involved there, and if a range isn't a 
 random-access range, it doesn't support any kind of indices 
 anyway. The compiler would have to add a variable to count the 
 elements, and it doesn't support that.
I understand. I guess I was expecting the compiler to automatically do something along the lines of what enumerate does. Although, a nicer error message would have saved the day just as well. Arredondo
Mar 02 2018
prev sibling parent reply bauss <jj_1337 live.dk> writes:
On Friday, 2 March 2018 at 10:21:39 UTC, Arredondo wrote:
 Hi,

 The following works as expected:

 auto range = [1, 2, 3, 4, 5];
 foreach (i, el; range) {
 	writeln(i, ": ", el);
 }

 but this slight modification doesn't:

 auto range = iota(5);
 foreach (i, el; range) {
 	writeln(i, ": ", el);
 }

 DMD 2.078.3 says:
 Error: cannot infer argument types, expected 1 argument, not 2

 The error message is not helpful either, because indicating the 
 types, as in:

 foreach (int i, int el; range) { ... }

 throws the same error.
 What's going on here?

 Arredondo
What you want to do is call "enumerate" from "std.range". auto range = iota(5).enumerate; foreach (i, el; range) { writeln(i, ": ", el); } You can also call "array" from "std.array". auto range = iota(5).array; foreach (i, el; range) { writeln(i, ": ", el); }
Mar 02 2018
parent Arredondo <arm.plus gmail.com> writes:
On Friday, 2 March 2018 at 10:34:31 UTC, bauss wrote:
 You can also call "array" from "std.array".

     auto range = iota(5).array;

     foreach (i, el; range) {
         writeln(i, ": ", el);
     }
Thank you. That's how I had it in my original code, I was just trying to avoid gratuitous memory allocation. Arredondo
Mar 02 2018