joiner: How to iterate over immutable ranges?

Jonathan M Davis via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Feb 14 10:28:11 PST 2016


On Sunday, February 14, 2016 15:24:39 Bastiaan Veelo via Digitalmars-d-learn wrote:
> Hi,
>
> I am having trouble getting the iteration methods in
> std.algorithm.iteration to work on immutable data:
>
> > import std.algorithm.iteration;
> > import std.stdio;
> >
> > void main()
> > {
> >     string[][] cycles;
> >     cycles ~= ["one", "two"];
> >     cycles ~= ["three", "four"];
> >     foreach (number; cycles.joiner) // This works.
> >         writeln(number);
> >
> >     immutable(string[])[] icycles;
> >     icycles ~= ["one", "two"];
> >     icycles ~= ["three", "four"];
> >     foreach (number; icycles.joiner)  // Should this work?
> >         writeln(number);
> > }
>
> The error message is:
>
> /d149/f840.d(15): Error: template std.algorithm.iteration.joiner
> cannot deduce function from argument types
> !()(immutable(string[])[]), candidates are:
> /opt/compilers/dmd2/include/std/algorithm/iteration.d(1911):
>    std.algorithm.iteration.joiner(RoR, Separator)(RoR r, Separator
> sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) &&
> isForwardRange!Separator && is(ElementType!Separator :
> ElementType!(ElementType!RoR)))
> /opt/compilers/dmd2/include/std/algorithm/iteration.d(2194):
>    std.algorithm.iteration.joiner(RoR)(RoR r) if (isInputRange!RoR
> && isInputRange!(ElementType!RoR))
>
> I had expected this to work. What did I miss?

An immutable range fundamentally does not work. The same goes with const. In
fact, a type that's immutable is going to fail isInputRange precisely
because it can't possibly function as one. While empty and front may be
callable on an immutable range, depending on their exact signatures,
popFront cannot be, because it has to mutate the range in order to work.

Arrays do typically get sliced when they're passed to functions, and array
slices are tail-const (e.g. const(int[]) is sliced as const(int)[]), so
something like

immutable string foo = "hello world";
auto result = foo.startsWith("goodbye");

will compile. But that doesn't work with ranges in general. What you're
doing is probably failing, because icycle[] is immutable(string)[], which is
immutable(char[])[], and it can't iterate over the immutable(char[]). But
regardless, if you try and use immutable with ranges, even if it works in
some cases thanks to how arrays are treated, it's just going to end up
shooting you in the foot in the end. So, I'd advise that you not bother
trying to do much with const or immutable with ranges.

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list