Filter and Map's weird return types cause frustration...

Allen Nelson ithinkican at gmail.com
Sat Feb 23 00:48:24 PST 2013


I'm trying to do some functional programming techniques on lists 
in D, and while I'm happy that there's some functionality to be 
found, some of (what I perceive as) the language's foibles don't 
make it as smooth as I'd like. Here's an example:

import std.stdio, std.algorithm;

void main() {
	string[][] example = [["a", "b", "sdflk"],
					   ["sdflkjsd", "sdl"],
					   ["sdfjhsdklfjh", "sdkjfh", "alskaslk"]];
	writeln(example);
	int i=2;
	bool isLongEnough (string[] slist) {return slist.length > i;}
	example = filter!(isLongEnough)(example);
	writeln(example);
}

It seems a perfectly valid desire, to have an array and want to 
prune it down into an array that satisfies certain requirements. 
After all, this is exactly what filter is supposed to do. This 
code seems fairly straightforward then, but trying to compile it:

> dmd test.d
test.d(10): Error: cannot implicitly convert expression 
(filter(reps)) of type FilterResult!(isLongEnough, string[][]) to 
string[][]

So essentially, the compiler is telling me that even though 
filter's whole raison d'etre is to take a data structure and 
return the same kind of data structure, but with some values 
possibly removed, it not only returns a weird in-house-brand 
"FilterResult" type, it can't even convert this into a into a 
string[][] type. Now, I could use "auto" instead of "string[][]", 
and it works, but I have no use for a "FilterResult". I don't 
know what methods I can call on it, or what it's made out of. I 
want a string[][].

A similar story happens with the map function. Map takes an array 
and a function and returns another array which is of values 
computed from applying the function to the input array. One would 
think, then that this code would work:

void main() {
	string[][] reps = [["a", "b", "sdflk"],
					   ["sdflkjsd", "sdl"],
					   ["sdfjhsdklfjh", "sdkjfh", "alskaslk"]];
	writeln(reps);
	int[] lengths = map!("a.length")(reps);
	writeln(lengths);
}

After all, the .length function returns an int, and we have an 
array of them, so map returns an int, right? Wrong!

dmd test.d
test.d(8): Error: cannot implicitly convert expression 
(map(reps)) of type MapResult!(unaryFun, string[][]) to int[]

Once again, even though the returned array is, for all intents 
and purposes, an int[], I can't call it that. Which means I can't 
concatenate onto an existing int[], for example.

Why are filter and map returning these weird one-off types in the 
first place? Why would filter return anything but the same type 
of list that it was passed as an argument? Why would map return 
anything other than an array of whatever type matches the return 
value of the operator? And if there's some good reason why these 
things are the case, why then at the very least would you not be 
able to easily cast the return type into the return type that you 
want?


More information about the Digitalmars-d mailing list