www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Passing iterators into functions

reply repr-man <jxl.ppg gmail.com> writes:
I have the code:

int[5] a = [0, 1, 2, 3, 4];
int[5] b = [5, 6, 7, 8, 9];
auto x = chain(a[], b[]).chunks(5);
writeln(x);

It produces a range of slices as is expected: [[0, 1, 2, 3, 4], 
[5, 6, 7, 8, 9]]

However, when I define a function as follows and pass in the 
result of the chain iterator:

auto func(R)(R r, size_t width)
if(isRandomAccessRange!R)
{
     return r.chunks(width);
}

void main()
{
     int[5] a = [0, 1, 2, 3, 4];
     int[5] b = [5, 6, 7, 8, 9];
     auto x = func!(int[])(chain(a[], b[]), 5);
     writeln(x);
}

It gives me an error along the lines of:
Error: func!(int[]).func(int[] r, ulong width) is not callable 
using argument types (Result, int)
        cannot pass argument chain(a[], b[]) of type Result to 
parameter int[] r

I was hoping it would return the same result as the first program.

This seems to have to do with the fact that all iterators return 
their own unique type.  Could someone help me understand the 
reason behind this design and how to remedy my situation?
Jun 24 2020
next sibling parent Max Haughton <maxhaton gmail.com> writes:
On Thursday, 25 June 2020 at 03:35:00 UTC, repr-man wrote:
 I have the code:

 int[5] a = [0, 1, 2, 3, 4];
 int[5] b = [5, 6, 7, 8, 9];
 auto x = chain(a[], b[]).chunks(5);
 writeln(x);

 It produces a range of slices as is expected: [[0, 1, 2, 3, 4], 
 [5, 6, 7, 8, 9]]

 However, when I define a function as follows and pass in the 
 result of the chain iterator:

 auto func(R)(R r, size_t width)
 if(isRandomAccessRange!R)
 {
     return r.chunks(width);
 }

 void main()
 {
     int[5] a = [0, 1, 2, 3, 4];
     int[5] b = [5, 6, 7, 8, 9];
     auto x = func!(int[])(chain(a[], b[]), 5);
     writeln(x);
 }

 It gives me an error along the lines of:
 Error: func!(int[]).func(int[] r, ulong width) is not callable 
 using argument types (Result, int)
        cannot pass argument chain(a[], b[]) of type Result to 
 parameter int[] r

 I was hoping it would return the same result as the first 
 program.

 This seems to have to do with the fact that all iterators 
 return their own unique type.  Could someone help me understand 
 the reason behind this design and how to remedy my situation?
Chain returns a range not an int[]. You need to either convert the range to an array via .array or allow the compiler to infer the type of the parameter of func (You'll need to import std.range to have the range interface available) mhh
Jun 24 2020
prev sibling next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
Collection elements are accessed by ranges in D. Although both iterators 
and ranges fundamentally do the same thing (access elements). More 
accurately, ranges correspond to a pair iterators.

On 6/24/20 8:35 PM, repr-man wrote:

 auto func(R)(R r, size_t width)
 if(isRandomAccessRange!R)
 {
      return r.chunks(width);
 }

 void main()
 {
      int[5] a = [0, 1, 2, 3, 4];
      int[5] b = [5, 6, 7, 8, 9];
      auto x = func!(int[])(chain(a[], b[]), 5);
Is there a reason why you specify the template argument there?
 This seems to have to do with the fact that all iterators return their
 own unique type.
When the element is normally different, there would be no way of using one type anyway. This is similar to how vector<int>::iterator is a different type from e.g. vector<double>::iterator.
 Could someone help me understand the reason behind
 this design
Andrei Alexandrescu has the following article on D's ranges: https://www.informit.com/articles/printerfriendly/1407357
 and how to remedy my situation?
Just don't specify the function template argument and it will work. Ali
Jun 25 2020
prev sibling parent Mike Parker <aldacron gmail.com> writes:
On Thursday, 25 June 2020 at 03:35:00 UTC, repr-man wrote:

 This seems to have to do with the fact that all iterators 
 return their own unique type.  Could someone help me understand 
 the reason behind this design and how to remedy my situation?
Ranges conform to well-defined interfaces. Given that the algorithms in Phobos are templates and use structs rather than classes, this means the interfaces are checked at compile time (see the `is*` templates in std.range.primitives [1]). It also means that there is no concrete range "type" returned by these functions. That's why all of them return `auto` instead of a specific type. You never need to know the specific type of a range. Arrays are ranges only because of the free-function implementation of the range interfaces in std.range.primitives which all take an array as the first argument so that they may be called using UFCS in any templated range algorithm. So when you input an array to a range algorithm, the algorithm has no idea it has an array. It just calls R.emtpy, R.front, etc., without ever caring what the actual type is. And you can chain them because each algorithm wraps the input range with custom range type that actually implements the algorithm (in e.g., `popFront`--that's also why ranges are lazy), and that's what is returned. In a chain of function calls, popFront is called on the outermost range, which calls popFront on its wrapped range, which calls popFront on its wrapped range, etc. So if you append std.array.array to the end of the chain, it will kick off execution of the whole chain of calls by making the first call to popFront in order to copy the result into a new array. Chapter 6, "Understanding Ranges", from "Learning D" is available freely online [2]. You should give it a read. [1] https://dlang.org/phobos/std_range_primitives.html [2] https://hub.packtpub.com/understanding-ranges/
Jun 25 2020