www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Unable to convert a MapResult to an InputRange.

reply Jake Pittis <jakepittis gmail.com> writes:
````
import std.stdio;
import std.array;
import std.algorithm;
import std.range;

InputRange!string keys(int[string] foo) {
   return foo.byPair.map!(p => p[0]);
}

void main() {
   int[string] foo;
   foo["lol"] = 1;
   foo["wat?"] = 2;
   keys(foo).each!(p => writeln(p));
}
````

The above code produces an `cannot implicitly convert expression 
(map(byPair(foo))) of type MapResult!(__lambda2, 
MapResult!(__lambda2, Result)) to 
std.range.interfaces.InputRange!string` error.

If I replace `InputRange!string` with `auto`, it compiles.

I'm intending to use InputRange!string as a return type in an 
interface so I can't use auto.

````
interface bar {
   InputRange!string keys();
}
````

I don't want to convert it to an array because of the allocation. 
Isn't the whole point of ranges to pass around a lazy interface 
without having to allocate any extra memory? Why can't I cast the 
output of map to an InputRange or something similar?

Thanks for the help. :) Phobos documentation is lovely but I've 
been finding errors similar to this to be quite frustrating.
Sep 18 2016
parent Jonathan M Davis via Digitalmars-d-learn writes:
On Monday, September 19, 2016 01:13:19 Jake Pittis via Digitalmars-d-learn 
wrote:
 ````
 import std.stdio;
 import std.array;
 import std.algorithm;
 import std.range;

 InputRange!string keys(int[string] foo) {
    return foo.byPair.map!(p => p[0]);
 }

 void main() {
    int[string] foo;
    foo["lol"] = 1;
    foo["wat?"] = 2;
    keys(foo).each!(p => writeln(p));
 }
 ````

 The above code produces an `cannot implicitly convert expression
 (map(byPair(foo))) of type MapResult!(__lambda2,
 MapResult!(__lambda2, Result)) to
 std.range.interfaces.InputRange!string` error.

 If I replace `InputRange!string` with `auto`, it compiles.

 I'm intending to use InputRange!string as a return type in an
 interface so I can't use auto.

 ````
 interface bar {
    InputRange!string keys();
 }
 ````

 I don't want to convert it to an array because of the allocation.
 Isn't the whole point of ranges to pass around a lazy interface
 without having to allocate any extra memory? Why can't I cast the
 output of map to an InputRange or something similar?

 Thanks for the help. :) Phobos documentation is lovely but I've
 been finding errors similar to this to be quite frustrating.
Almost no one uses the InputRange interface, and if you do you use, you _will_ be allocating memory, because it's going to involve allocating a class object on the heap. Ranges are normally templated structs, not classes, and aren't convertible to any kind of interface. So, the only way for them to work as an interface is to wrap them in a class. It looks like the inputRangeObject function in std.range.interfaces can be used to create a class object that wraps a range, but it _will_ be allocating that object on the heap unless it happens to be a class which implements InputRange (which is true for almost no ranges). ange-based code is generally expected to all be templatized and use auto aside from the points where you want to convert a range to a dynamic array. And that works well pretty much everywhere except for virtual functions, which can't be templated. So, if you're stuck with that, and you don't want to convert your range to a dynamic array, then you're going to need to do something like use inputRangeObject to allocate a class object that wraps the range that you're dealing with. But I'd suggest that you avoid trying to deal with ranges as interfaces if you can. - Jonathan M Davis
Sep 18 2016