Background
The return
attribute allows you to return a scope variable.
The compiler knows that the returned value has the same lifetime as the argument passed to the function.
// ┌───────────<──────────┐
int* identity(return int* x) @safe {
return x;
}
void main() @safe {
int x;
// ┌──────<──────┐
int* y = identity(&x);
static int* z; // global variable
z = y; // error! scope variable `y` assigned to non-scope `z`
}
What if you are not using a return value, but setting it to another parameter, e.g. using ref
or out
?
// ┌─────────<─────────┐
void assign(ref scope int* target, return int* source) @safe {
target = source;
}
The compiler knows that source
cannot be returned since it's a void
function, so it makes the first parameter, but only the first parameter, the destination of the return
parameter source
.
void main() @safe {
int x;
int* y;
// ┌─<─┐
assign(y, &x); // allowed
}
This feature has been proposed and implemented by Walter Bright: Issue 19097, fix Issue 19097 - Extend Return Scope Semantics.
It was merged on January 2019, but in August 2018 there was a discussion about it:
Re: Is @safe still a work-in-progress?
Mike Franklin:
>Why not the first ref
parameter regardless of whether it's the absolute first in the list. Why not the last ref
parameter? Why not all ref
parameters?
Walter Bright:
>Good question. If this fairly restricted form solves the problems, then there is no need for the more flexible form. Things can always be made more flexible in the future, but tightening things can be pretty disruptive. Hence, unless there is an obvious and fairly strong case case for the flexibility, then it should be avoided for now.
So did the restricted form turn out to be good enough? Well, on March 23 2019, Build entire Phobos with -preview=dip1000 #6931 was merged, so it seems to be. Hurray!
Except... It turns out we're not quite done yet, because Druntime and Phobos still rely on a pretty major accepts-invalid bug to compile with -dip1000, see:
dip1000 + pure is a DEADLY COMBO
The good news is, Per Nordlöw and I have been working on fixing Phobos, and Druntime [1], [2], [3], [4] (also thanks to aG0aep6G, Walter Bright, Iain Buclaw, and reviewers). During this, we did stumble on cases where the restriction came up, such as BigUint.divMod having out
parameters after the input parameters. More importantly:
The issue
It turns out that core.lifetime: move
(which is also in Phobos), has a signature that's incompatible with -dip1000 in its current form:
void move(T)(ref T source, ref T target)
We want to express:
// ┌─────────>─────────┐
void move(T)(return T source, ref scope T target)
But there's currently now way of making target
the return scope destination when it's not the first parameter. So unless we want to leave move
@system
or create a move2
function with parameters reversed, we're back at the drawing board for "Extend Return Scope Parameters". Two earlier proposals were:
// Mike Franklin's proposal:
void move(T)(return(target) T source, ref scope T target)
// Steven Schveighoffer's proposal:
void move(T)(return T source, @__sink ref scope T target)
What do you think?