On 02/14/2016 11:32 AM, Bastiaan Veelo wrote:

> Thanks. I didn't know that iterating a range means mutating its
> contents.

That's not the case: Just like an iterator, a range must maintain some state to know which item is next. What needs to be mutated is that iteration state.

> I still don't quite get it, and it is probably because I don't
> fully understand ranges. I think what confuses me the most is their
> analogy to containers.

Yes, that analogy is the wrong one (and D's slices (or dynamic arrays) don't help with that).

> It's no problem to iterate over a container of immutable data, but
> it is for a range.

Not true. You can iterate over immutable data. In fact, a string is nothing but a container of immutable characters yet we can iterate over it.

> I thought that joiner provided a contiguous view on distinct ranges,
> without needing to touch these. Is there another method to traverse a
> range of ranges without making copies or mutation?

Not without making copies but note that the copy that you need to make is just the slices (i.e. views into data), which consist of just a length and a pointer fields. If it's acceptable for you, the following code calls .save on the elements and it works:

import std.algorithm.iteration;
import std.stdio;
import std.array;    // <-- ADDED

void main()
{
    immutable(string[])[] icycles;
    icycles ~= ["one", "two"];
    icycles ~= ["three", "four"];
    foreach (number; icycles.map!(r => r.save).joiner)
        writeln(number);
}

Again, .save on an array is cheap. What will happen is that the original immutable arrays will be untouched but their proxies returned by .save will be consumed.

Ali

Reply via email to