joiner: How to iterate over immutable ranges?

Ali Çehreli via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Feb 14 17:14:10 PST 2016


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



More information about the Digitalmars-d-learn mailing list