www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 24570] New: printing a range of ranges consumes sub-ranges

https://issues.dlang.org/show_bug.cgi?id=24570

          Issue ID: 24570
           Summary: printing a range of ranges consumes sub-ranges
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: phobos
          Assignee: nobody puremagic.com
          Reporter: schveiguy gmail.com

If you are printing something, you might correctly not expect the act of
printing it to modify that type.

However, printing a range *requires* that you modify it. It's how you get at
the elements inside. For this reason, a range must be treated as a *view* of
data, not the thing to print.

If you print a range whose elements are ranges, those elements should behave as
if you printed them. That is, the act of printing them should not modify the
elements themselves.

However, currently `formatValue` will accept range elements by reference, and
print them by iterating them. This means that a range-of-ranges where the outer
range uses lvalue elements will consume all the nested ranges.

An example:

```d
import std.range;
import std.conv;
import std.algorithm;
struct R
{
    int* ptr;
    size_t len;
    int front() {return  *ptr;}
    void popFront() { ++ptr; --len; }
    bool empty() {return len == 0;}
    typeof(this) save() { return this; }
}

void main()
{
    import std.conv;
    auto intarr = [1, 2, 3];
    auto r = R(intarr.ptr, intarr.length);
    assert(text(r) == "[1, 2, 3]"); // ok, r is passed by value
    assert(text(r) == "[1, 2, 3]"); // still there
    auto ndarr = [r, r]; // a range of ranges
    assert(text(ndarr) == "[[1, 2, 3], [1, 2, 3]]"); // ok, but this consumed
the subranges
    assert(text(ndarr) == "[[], []]"); // now they are gone
    ndarr = [r, r];

    // what phobos should do, is save every forward range before printing
    assert(text(ndarr.map!(e => e.save)) == "[[1, 2, 3], [1, 2, 3]]"); // ok
    assert(text(ndarr.map!(e => e.save)) == "[[1, 2, 3], [1, 2, 3]]"); // ok
}
```

Note: I used text instead of writeln so the asserts can be written, but the
same thing happens with writeln.

--
May 27