On Friday, 17 November 2017 at 03:15:12 UTC, Tony wrote:
Thanks T! Good information, especially "iterating over a range is supposed to consume it". I have been reading dlang.org->Documentation->Language Reference, but should have also read dlang.org->Dlang-Tour->Ranges. Although that page
You might also find use in this article (poorly adapted from Chapter 6 of Learning D by the publisher, but still readable):
https://www.packtpub.com/books/content/understanding-ranges
makes a distinction about "range consumption" with regard to a "reference type" or a "value type" and it isn't clear to me why there would be a difference.
With a value type, you're consuming a copy of the original range, so you can reuse it after. With a reference type, you're consuming the original range and therefore can't reuse it.
======== struct ValRange { int[] items; bool empty() @property { return items.length == 0; } int front() @property { return items[0]; } void popFront() { items = items[1 .. $]; } } class RefRange { int[] items; this(int[] src) { items = src; } bool empty() @property { return items.length == 0; } int front() @property { return items[0]; } void popFront() { items = items[1 .. $]; } } void main() { import std.stdio; int[] ints = [1, 2, 3]; auto valRange = ValRange(ints); writeln("Val 1st Run:"); foreach(i; valRange) writeln(i); assert(!valRange.empty); writeln("Val 2nd Run:"); foreach(i; valRange) writeln(i); assert(!valRange.empty); auto refRange = new RefRange(ints); writeln("Ref 1st Run:"); foreach(i; refRange) writeln(i); assert(refRange.empty); writeln("Ref 2nd Run:"); foreach(i; refRange) writeln(i); // prints nothing }