Why can't I give a function's return type the scope storage class?

Meta jared771 at gmail.com
Tue Mar 19 03:48:15 UTC 2019


Okay, one more question. I might be misunderstanding how DIP1000 
works, but I cannot figure out how to copy data owned by an inner 
scope to an outer scope. I know that `scope` is supposed to 
prevent this, but in my case it's perfectly fine, as I am 
transferring ownership of the data from the inner scope to a data 
store in the outer scope (e.g., copying some data in a 
deeper-nested scope into an outer array). However, I can't seem 
to get the compiler to understand this transfer of ownership (I 
also tried moving values with std.algorithm.move).

My example code is a bit too long to post here, but it can be 
found at https://run.dlang.io/is/e6Lc15. The main crux of this 
issue is:

@safe
Queue!Data copyToQueue(DataRange data)
{
     Queue!Data output;
     while (!data.empty)
     {
         auto d = data.front;
         data.popFront();
         import std.random: uniform;
         if (uniform(0, 100) < 50)
         {
             output.push(d);
         }
     }
     return output;
}

And the definition of Queue!T.push is:

     @safe
     void push(return scope T val) scope
     {
         ptr += 1;
         if (ptr >= store.length && ptr < size_t.max)
         {
             store.length = store.length == 0
                 ? 8
                 : store.length * growthFactor;
         }
         //FIXME: either I don't understand DIP1000
         //well enough, or this should compile
         //Workaround: surround it with an @trusted lambda
         store[ptr] = val;
     }

 From my understanding of DIP1000, annotating `val` with `return 
scope` in `Queue.push` tells the compiler "this value can only 
escape by being returned from the function, or being copied into 
the first parameter" (in this case, the first parameter being the 
`this` reference). Then, marking `Queue.push` as `scope` also 
tells the compiler "no references to `this` may escape from this 
function".

In this case, the Queue I am copying data into is in an outer 
scope, and the data I'm copying is `scope` (see the code at my 
link). The problem is that the compiler doesn't like this; it's 
telling me "Error: scope variable val assigned to non-scope 
this.store[this.ptr]". This is confusing, though, because I 
thought that's exactly why there's this special proviso for 
`return` and `return scope`:

"If the function returns void, and the first parameter is ref or 
out, then all subsequent return ref parameters are considered as 
being assigned to the first parameter for lifetime checking. The 
this reference parameter to a struct non-static member function 
is considered the first parameter."

As long as I'm not escaping the `this` reference from 
`Queue.push`, shouldn't the lifetime analysis all check out?


More information about the Digitalmars-d mailing list