Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

result of std.algorithm.map

Tags:

types

map

d

Could somebody say what std.algorithm.map returns? (link to some documentation page would be very appreciated) From error message its result is of type Result

ulong[] x = [1,2,3];
ulong[] y = std.algorithm.map!"a"(x); // Error: cannot implicitly convert <..> of type Result to ulong[]

In http://dlang.org/phobos/std_algorithm.html#map there is quite little info on it:

The call map!(fun)(range) returns a range of which elements are obtained by applying fun(x) left to right for all x in range

From this it is not clear, what I can or can not do with it.

like image 642
dnsmkl Avatar asked May 03 '12 18:05

dnsmkl


3 Answers

You're not supposed to know or care what std.algorithm.map returns beyond the fact that it's a range of the same genre as the one passed in (forward, bidirectional, random, etc.). It's that way with most range-based functions. They almost always return either a new range which wraps the one passed in or a the exact same type of range as was passed in (e.g. map does the former; find does the latter). Use auto:

ulong[] x = [1, 2, 3];
auto y = map!"a"(x);

The range returned by map is lazy. It doesn't do anything until you iterate over it (it then calls the given function on each successive front of the underlying range). It's more efficient that way (as well as enabling infinite ranges). The exact return type depends on the type of range that you passed in and is local to map so that you can't create one directly. You need to either use auto to infer the type or typeof to get the type:

typeof(map!"a"(x)) y = map!"a"(x);

However, you generally only use typeof when you need a variable which you cannot initialize directly. auto is almost always the way to go.

If you need to create an array from the result of map (or from any other range), then use std.array.array:

ulong[] y = array(map!"a"(x));

If you don't know much about ranges, then you should probably read this. Unfortunately, there isn't currently an article on dlang.org explaining ranges, but that link is for a chapter in a book which one of the members of the D community wrote in Turkish and has been translating to English, and it covers ranges fairly well.

EDIT:

Walter Bright recently wrote an article specifically about types which are local to a function but returned by the function which may also help enlighten you. They even get a cool name: Voldemort Types in D.

like image 158
Jonathan M Davis Avatar answered Sep 20 '22 11:09

Jonathan M Davis


The Result range is 'lazy', it doesn't represent the final result.

It can be turned into an array if you import std.array and wrap it like so:

ulong[] y = array(std.algorithm.map!"a"(x));

or

ulong[] y = std.algorithm.map!"a"(x).array;

if you are using dmd 2.059 or later

The map result can also be iterated over directly with foreach:

auto result = std.algorithm.map!"a"(x);
foreach (element; result)
  writeln(to!string(element));
like image 21
OlaOst Avatar answered Sep 22 '22 11:09

OlaOst


Result is a type inside map() that cannot be named because it is a Voldemort Type.

The actual source code in Phobos looks something like this:

template map(fun...) if (fun.length >= 1)
{
    auto map(Range)(Range r) if (isInputRange!(Unqual!Range))
    {
        //...
        struct Result
        {
            //...
        }
        return Result(r);
    }
}

If you study the source code you will notice that Result is nothing but a range: it has the usual popFront() and empty() methods, and other methods depending on the kind of range that needs to be returned. If you use type inference,

auto r = map!("a*a")(data);

r will be typed as Result, but you can't directly instantiate it.

like image 28
Arlen Avatar answered Sep 20 '22 11:09

Arlen