On Friday, 13 July 2012 at 22:27:01 UTC, Jonathan M Davis wrote:
On Friday, July 13, 2012 14:11:44 monarch_dodra wrote:
But I still feel that the internal call to opSlice/copy is really
a just trap disguised as a safety net...

Yeah. Kind of.

The thing is that there's no way around the fact that structs and arrays are effectively value types as far as ranges go, whereas classes are reference types. If you want them to be copied consistently, you need to use save. If you don't care whether a copy is made or not, then you don't worry about it.

But foreach has to be treated specially with ranges anyway, because of
strings.

foreach(e; str) {}

is going to iterate over char, not dchar, whereas strings are ranges of dchar.
So, if you iterate over a range generically, you need to do

foreach(ElementType!R e; range) {}

So, you have to be careful with foreach already, and having it _not_ save but having it copy the range automatically (and therefore implicitly saving for non-reference type forward ranges) is completely consistent with how it works with passing ranges to functions, so in that sense, it really isn't all that
bad. If anything, things are _more_ consistent that way.

The only way to really solve the save problem would be to disallow forward ranges which were reference types (which you could mostly do by disallowing classes, but I don' think that there's any real way to statically check whether a struct is a reference type or not). Then save wouldn't be needed, and ranges would all function the same as long as no one made structs which were reference types into ranges. But that would also cut off some useful idioms (sometimes, you _want_ a range to be consumed by a function rather than being implicitly copied - which is why I added std.range.RefRange for 2.060). So, I don't know of any way to really fix the problem. You need save to make it possible to copy reference types, and there's no way to reasonably avoid
having to deal with both value type and reference type ranges.

So, we just deal with it. Unfortunately, far too often, the result of that is that value type ranges work properly and reference type ranges don't, since range-based functions are usually tested with just value types ranges, but
improved testing fixes that, and that's not all that hard to do.

- Jonathan M Davis

Very good points. I appreciate your answer.

I guess I should consider the "copy" the standard byproduct of "passing to foreach" => I should _also_ remember to save before passing a range to a function.

Reply via email to