Bug with writeln?

Steven Schveighoffer schveiguy at gmail.com
Thu Sep 6 18:21:24 UTC 2018


On 9/6/18 12:55 PM, Jonathan M Davis wrote:
> On Thursday, September 6, 2018 2:40:08 AM MDT Saurabh Das via Digitalmars-d-
> learn wrote:
>> Is this a bug with writeln?
>>
>> void main()
>> {
>>       import std.stdio, std.range, std.algorithm;
>>
>>       auto a1 = sort([1,3,5,4,2]);
>>       auto a2 = sort([9,8,9]);
>>       auto a3 = sort([5,4,5,4]);
>>
>>       pragma(msg, typeof(a1));
>>       pragma(msg, typeof(a2));
>>       pragma(msg, typeof(a3));
>>
>>       auto b = [a1, a2, a3];
>>       pragma(msg, typeof(b));
>>
>>       writeln("b:");
>>       writeln(b);
>>       writeln(b);  // <-- this one prints incorrectly
>>
>>       writeln("a:");
>>       writeln(a1);
>>       writeln(a2);
>>       writeln(a3);
>>
>> }
>>
>> Output
>> ======
>>
>> SortedRange!(int[], "a < b")
>> SortedRange!(int[], "a < b")
>> SortedRange!(int[], "a < b")
>> SortedRange!(int[], "a < b")[]
>> b:
>> [[1, 2, 3, 4, 5], [8, 9, 9], [4, 4, 5, 5]]
>> [[], [], []]
>> a:
>> [1, 2, 3, 4, 5]
>> [8, 9, 9]
>> [4, 4, 5, 5]
>>
>> The issue goes away if I cast 'b' to const before writeln. I
>> think it is a bug, but maybe I am missing something?
> 
> 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.

-Steve


More information about the Digitalmars-d-learn mailing list