Arguably, the goal is to actually replace "repeat+map". I view
the fact that iota not being infinite as a drawback. And even
if you do want a bound to the length of your range, I believe
it should be the "top" step in your types, as opposed to the
"bottom" step. Eg:
iota(n).map!(_ => letters[uniform(0, $)]).array;
vs
repeat(0).map!(_ => letters[uniform(0, $)]).take(n).array;
*Personally*, I prefer the logic behind the repeat+map+take,
over iota+map's. It might actually even be faster. It is
slightly more verbose though :/
There is a way to have an infinite generate range and also a
convenient way to initialize arrays - just add an overload of
array() that takes the length as the second parameter. Then we
can do:
auto randomString = generate!(() => letters[uniform(0,
$)]).array(10);
------
Another advantage "generate" would have over repeat+map is if
you want to pass an actual named impure function (as opposed to
lambda):
iota(0, n).map(_ => fun());
or
repeat(0).map(_ => fun()).take(n);
vs
fastGenerate!fun().take(n);
Here, the generate would be much more "idiomatic", and also
probably easier on the compile (function vs lamba: easier
inlining, as you mention below).
In general, named functions and lambdas are pretty much
equivalent in regard to inlining (see http://goo.gl/XaOUP). In
your example, the last line could be more efficient than the
first two, because in the first two lines there could be one
extra function call in the worst case.
Another thing I'd like to re-bring up (which I've partially
implemented already), was bearophile's pass/tee suggestion:
http://forum.dlang.org/thread/[email protected]
I agree this is a good idea.