Move semantics for D

monarch_dodra monarch_dodra at gmail.com
Fri Jul 13 04:45:19 PDT 2012


On Friday, 13 July 2012 at 10:33:13 UTC, Jonathan M Davis wrote:
> On Friday, July 13, 2012 12:24:45 monarch_dodra wrote:
>> On Friday, 13 July 2012 at 09:47:26 UTC, Jonathan M Davis 
>> wrote:
>> > On Friday, July 13, 2012 11:23:41 monarch_dodra wrote:
>> >> I think that in the case of your example, if "range" 
>> >> fulfills
>> >> the
>> >> requirements for (at least) an input range, then "save"
>> >> *should*
>> >> be called instead of "opSlice". I'm *think* this is what the
>> >> compiler does, but I'm not 100% sure.
>> > 
>> > The compiler never calls save. It will call opSlice on
>> > non-ranges, but it'll
>> > never call save on anything. It doesn't even know that save
>> > exists. It's
>> > unnecessary for ranges which aren't reference types, and you
>> > already have to
>> > worry about calling save on ranges that could be reference
>> > types any time that
>> > you pass them to a function that you don't want to consume 
>> > it,
>> > so it's not
>> > really a big deal to have to call save with foreach for such
>> > ranges. Most
>> > range-based functions don't even use foreach much anyway.
>> > 
>> > - Jonathan M Davis
>> 
>> What exactly are the semantics of save? The reference in
>> std.range isn't very clear. It would appear it is only useful 
>> it
>> its *existence* that promotes a range from input to forward.
>> However, how is it different from a simple assignment?
>> 
>> Also, if you are supposed to call save before a foreach
>> "consumes" your range, then why does foreach even bother 
>> making a
>> copy of the range before iterating on it? Isn't this behavior
>> promoting dangerous usage for ranges where save is simply
>> "{return this;}", but bites you in the ass the day you use a
>> range with a specific save?
>> 
>> I'm confused...
>
> save exists so that classes can be forward ranges. Arrays and 
> most structs are
> copied when you assign them to another variable or pass them to 
> a function,
> but classes aren't. So, save was introduced to make it so that 
> there is a way
> to explicitly copy a range. It becomes useful even for structs 
> and arrays in
> that it documents that you're copying it, but it's outright 
> necessary for
> classes. Unfortunately, since arrays and structs are by far the 
> most common
> range types, save doesn't get used anywhere near as much as it 
> should be.
> Basically, you use save if you want to guarantee that the range 
> is copied, and
> you don't use save if you don't care.
>
> You can also look at this:
>
> http://stackoverflow.com/questions/11190204/how-do-you-use-ranges-in-
> d/11194827#11194827
>
> - Jonathan M Davis

I guess that "save" makes sense thanks in that context. Thank you.

However, foreach is starting to look very dangerous to me: Isn't 
the fact that it (potentially) calls opSlice, or makes a copy of 
your input just a asking for potential problems? Or is this a 
"struct vs class" issue, that I do not yet fully grasp?

Shouldn't we instead enforce an _explicit_ opSlice/save? Eg:
auto SomeContainer = ... ;
auto SomeRange = SomeContainer[ ... ];

foreach(v; SomeContainer[]) ... ; //Fine, iterate on a new range, 
and consume that
foreach(v; SomeRange.save)  ... ; //Fine, iterate on a copy of 
the range, and comue that

foreach(v; SomeContainer) ... ; //Fine, I will NOT call opSlice, 
and _consume_ your container
foreach(v; SomeRange)  ... ; //Fine, I will NOT copy, and 
_consume_ your range

...

I suppose the "recommendation" is to use the above form, and that 
is what I will be doing as of now on.

But I still feel that the call to opSlice/copy is really a just 
trap disguised as a safety net...


More information about the Digitalmars-d mailing list