On Fri, Jan 16, 2015 at 06:34:08PM +0000, Tobias Pankrath via Digitalmars-d wrote: > On Friday, 16 January 2015 at 18:12:03 UTC, Joseph Rushton Wakeling wrote: > >On Friday, 16 January 2015 at 17:22:42 UTC, Tobias Pankrath wrote: > >>Ah, now I understand you. Since copy-construction is undefined for > >>ForwardRanges, you cannot guarantee this. Things would be better, if > >>we had required that this(this) does the same as .save or must be > >>@disabled. > > > >I'm not sure I follow what you mean by this ... ? > > If you pass a forward range of type T (something that passes > isForwardRange!T) to a function you have no guarantees on what will > happen. It could be: > > • compilation failure > • reference semantics (changes are reflected outside the function > • value semantics (no change are reflected outside the function)
* The range is left in an inconsistent state. :-) > The implementer of the range can choose one. Although I tried it now, > and @disable this(this) does prevent isForwardRange!T to pass. I don't > know if that changed recently or is just out of line with the > documentation/specification. IIRC, this is because the test checks if it's possible to assign the range to a local variable. This is quite widely used in Phobos; @disable this(this) would make the range unusable with a *lot* of Phobos algorithms. In fact, pretty much *all* wrapper algorithms that have to assign the range to a field in the wrapper range. Besides, I think this approach doesn't really address the root of the problem, which is that the semantics of assigning a range (without using .save) is not specified by the range API. Yet code like `auto r = range;` is used all over the place in Phobos code, with various hidden assumptions about what '=' does, which may or may not correspond with reality. Ultimately, this is also the root cause of the transient range problem: the range API did not specify the semantics of `auto x = range.front;`. It's simply assumed that this copies the value of range.front... which, in a sense, it does, but what's hidden behind the '=' can be very complex semantics that breaks the algorithm's assumptions. In this case, it breaks because when range.front is a reference to a buffer reused by popFront, this causes the unexpected result that calling popFront also changes x. Had the range API specified the expected behaviour of assigning .front to a variable, this problem would not have arisen, or at least the possible problems would have been anticipated, instead of transience coming to bite us from behind when we least expect it. T -- I think the conspiracy theorists are out to get us...
