Printing a range of ranges drains them

Jonathan M Davis newsgroup.d at jmdavisprog.com
Mon May 27 06:31:37 UTC 2024


On Sunday, May 26, 2024 6:25:42 PM MDT Steven Schveighoffer via Digitalmars-d 
wrote:
> If you print a range of ranges (that are not arrays) with
> `writeln`, even if the nested range is a forward range, `writeln`
> will drain the nested ranges.
>
> example:
>
> ```d
> import std.stdio;
> import std.range;
> 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; }
> }
>
> static assert(isForwardRange!R);
>
> void main()
> {
>      int[] arr = [1, 2, 3];
>      auto r = R(arr.ptr, arr.length);
>      R[] mdarr = [r, r, r];
>      writeln(mdarr);
>      writeln(mdarr);
> }
> ```
>
> Output:
>
> ```
> [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
> [[], [], []]
> ```
>
> If you do this with nested arrays, it does not drain the inner
> arrays.
>
> You can fix by un-reffing the elements of the outer array:
> `writeln(mdarr.map!(e => e));`
>
> So, does anyone expect this behavior? If so, can you explain why
> you think this is intentionally designed this way?
>
> I wanted to file a bug, but I was shocked that this behavior as
> far as I can tell has always existed, and nobody has ever filed a
> bug on it.

I don't recall ever really thinking about it. I don't think that it's
something that I've done very often, and when I have, it was probably for
debugging. And in many cases, if you want readable input, it makes sense to
use foreach to loop through the outer range and print out each inner range
individually, in which case, you can call save on the inner ranges. That's
usually what I'd do if I know that I'm printing out a range of ranges.

Given that writeln needs to work with basic input ranges, having it not
consume the inner ranges would result in different behavior between basic
input ranges and forward ranges, which wouldn't be great. So, arguably,
having it consume them is the correct choice, but I'd have to spend a fair
bit of time thinking through the implications to come to a properly informed
conclusion.

Realistically though, I expect that it's an issue that was never really
thought through, and the current behavior is accidental whether it's truly
desirable behavior or not.

- Jonathan M Davis





More information about the Digitalmars-d mailing list