On 9/6/18 2:52 PM, Jonathan M Davis wrote:
On Thursday, September 6, 2018 12:21:24 PM MDT Steven Schveighoffer via
Digitalmars-d-learn wrote:
On 9/6/18 12:55 PM, Jonathan M Davis wrote:
It's not a bug in writeln. Any time that a range is copied, you must not
do _anything_ else with the original unless copying it is equivalent to
calling save on it, because the semantics of copying a range are
unspecified. They vary wildly depending on the range type (e.g. copying
a dynamic array is equivalent to calling save, but copying a class
reference is not). When you pass the range to writeln, you must assumed
that it may have been consumed. And since you have range of ranges, you
must assume that the ranges that are contained may have been consumed.
If you want to pass them to writeln and then do anything else with
them, then you'll need to call save on every range involved (which is a
bit of a pain with a range of ranges, but it's necessary all the same).

This is not necessarily true. It depends how the sub-ranges are returned.

The bug is that formattedWrite takes ranges sometimes by ref, sometimes
not.

formattedWrite should call save on a forward range whenever it makes a
copy, and it doesn't.

Case in point, it doesn't matter if you call writeln(b.save), the same
thing happens.

That's still not a bug in formattedWrite. save only duplicates the
outer-most range. And since writeln will ultimately iterate through the
inner ranges - which weren't saved - you end up with them being consumed.

That is the bug -- formattedWrite should save all the inner ranges (writeln calls formattedWrite, and lets it do all the work). To not do so leaves it open to problems such as consuming the sub ranges.

I can't imagine that anyone would expect or desire the current behavior.

Ironically, when that bug is fixed, you *don't* have to call save on the outer range!

When you're passing a range of ranges to a function, you need to recursively
save them if you don't want the inner ranges in the original range to be
consumed. Regardless of what formattedWrite does, it's a general issue with
any function that you pass a range of ranges. It comes right back to the
same issue of the semantics of copying ranges being unspecified and that you
therefore must always use save on any ranges involved if you want to then
use those ranges after having passed them to a function or copy them doing
anything else. It's that much more annoying when you're dealing with a range
of ranges rather than a range of something else, but the issue is the same.


It's only a problem if the subranges are returned by reference. If they aren't, then no save is required (because they are already copies). The fix in this case is to make a copy if possible (using save as expected).

I think the save semantics have to be one of the worst designs in D.

-Steve

Reply via email to