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