Printing a range of ranges drains them
Steven Schveighoffer
schveiguy at gmail.com
Mon May 27 14:01:44 UTC 2024
On Monday, 27 May 2024 at 06:31:37 UTC, Jonathan M Davis wrote:
>
> 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.
This is what `writeln` does (loops over the individual elements).
You can even format the nested ranges using `writefln` and the
`%(...%)` format specifier.
> 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.
I don't think you are grasping how surprising this is. If you are
debugging something, and you want to see what something looks
like at the moment, you print it. In this case, the act of
printing modifies the thing you are debugging! And it doesn't
even look like it did anything, because it printed fine. It's
only on the second printing you see there is a problem. So you
think "what happened between the first printing and the second
printing?".
This is actually the use case I was looking at yesterday when I
discovered (probably rediscovered) this issue. Would you expect
printing a struct to modify the struct? Well, it does if it
includes one of these range-of-ranges!
Note also, if you make the outer range by-ref, it will consume
all the inner ranges *but not the outer range, even if it uses
by-ref elements*. In other words, it has different behavior on
the outer range, vs the inner range. This is because `writeln`
accepts its parameters by value, but the underlying `formatValue`
uses auto ref (to support non-copyable range elements).
And, by the way, nested arrays are not consumed, even if they are
inside a range with lvalue elements. So that is another outlier.
And also likely why nobody has complained about this -- most
people use arrays for their ranges.
> 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.
I tend to agree. I'm going to file an issue on it. I think any
forward ranges should be passed via `.save` to their respective
formatters. This should fix the problem, and is what most people
would expect.
When I posed this question, my thought was that the behavior was
unintuitive, but given the length of time this has existed, I
thought maybe someone has a good reason why the code is this way,
and I'm just not seeing it.
Note for the range redesign -- this is going to make things
tricky as we won't have a `save` to use. We will have to
explicitly copy the range before passing to the `formatValue`
function (as long as it's a forward range). This is kind of a
drawback, I'll put that on the range redesign thread.
-Steve
More information about the Digitalmars-d
mailing list