On Sunday, 13 June 2021 at 11:59:49 UTC, ZachAttack! wrote:
> Challenge: Provide a code example illustrating how the existing variant of move
compiles when it shouldn't—or errors when it shouldn't—while the alternative form works correctly.
I actually couldn't do it... it may be harder than we suspect.
Ok I found out how to do it. It requires the arguments being passed to move
to be qualified with scope
:
void move1(ref int* source, scope ref int* target) @safe {
target = source;
}
void move2(scope ref int* target, return ref int* source) @safe {
target = source;
}
void main() @safe {
scope int* src;
scope int* tgt;
move2(tgt, src); // pass
move1(src, tgt); // Error: scope variable `src` assigned to non-scope parameter
() @trusted{ move1(src, tgt); }(); // passes correctly
}
The source
parameter in move1
above cannot be marked scope
without an error. Thus, the error when move1
is called is unavoidable.
Apparently, only those move
s involving scope
variables—a very small percentage—will be falsely flagged by the compiler as unsafe.
If this is the only price that is being paid for the language limitation, it would seem impossible to justify a language change.
Therefore, I suspect Walter's "simple" solution, involving no language change, is the best one.
However, marking move
(or functions like it) as @system
is overkill.
Since only a very small percentage of calls to move
and similar functions will be flagged wrongly, I believe the right solution is to document functions of this form, saying that otherwise @safe
calls to them may occasionally need to be wrapped in @trusted
blocks, to avoid the compiler falsely identifying them as having escaping pointers.