When does take modify the underlying iterator?

ag0aep6g via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Aug 16 14:34:29 PDT 2016


On 08/16/2016 11:01 PM, cy wrote:
> auto failhard(T)(T iter) {
[...]
>     writeln("We take 1 from it...");
>     writeln(iter.take(1));

This line may or may not pop the first element of the original iter.

That's because copying a range may or may not be same as calling .save 
on it. For many forward ranges it is the same, and then the original 
iter is unaffected. For true input ranges (that cannot be forward 
ranges), it cannot be the same. In that case, the original iter is 
invalidated, and must not be used anymore.

Whenever you want to keep using a range after passing it to some 
function, either .save it or make sure it acts like a reference. You've 
got reference behavior when the function uses a `ref` parameter, or when 
the range is a class/pointer, or when you use std.range.refRange to 
force it.

>     writeln("The rest of the range has:");
>     writeln(iter.drop(1).array);
>     writeln("");
> }

As for the example, you can rewrite it like so:

----
auto failhard(T)(T iter) {
     import std.stdio;
     import std.range: take, drop, refRange;

     writeln("We have some range:");
     writeln(typeid(T));
     writeln("We take 1 from it...");
     writeln(refRange(&iter).take(1));
     writeln("The rest of the range has:");
     writeln(iter);
     writeln("");
}
----

Also need to add @property to `front` and `empty` in the ranges. 
refRange is picky about this.


More information about the Digitalmars-d-learn mailing list