Unable to convert a MapResult to an InputRange.

Jonathan M Davis via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Sep 18 18:42:57 PDT 2016


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



More information about the Digitalmars-d-learn mailing list