On Wednesday, 21 March 2018 at 17:13:40 UTC, Jack Stouffer wrote:
Consider this example simplified from this PR https://github.com/dlang/phobos/pull/6281

------
struct GetoptResult
{
    Option[] options;
}

struct Option
{
    string optShort;
    string help;
}

GetoptResult getopt(T...)(scope T opts) @safe
{
    GetoptResult res;
    auto o = Option(opts[0], opts[1]);
    res.options ~= o;
    return res;
}

void main() @safe
{
    bool arg;
    getopt("arg", "info", &arg);
}
------

$ dmd -dip1000 -run main.d

------
main.d(16): Error: scope variable o assigned to non-scope res
main.d(23): Error: template instance `onlineapp.getopt!(string, string, bool*)` error instantiating
------

The only way I've found to make the code compile and retain the pre-dip1000 behavior is to change the Option construction to

------
auto o = Option(opts[0].idup, opts[1].idup);
------

How can we return non-scoped result variables constructed from scope variables without copies?

I thought that maybe adding a function to Option and marking it as `scope` would work:

struct GetoptResult
{
    Option[] options;
    void addOptions(scope Option opt) @safe scope
    {
        //Error: scope variable opt assigned to non-scope this
        options ~= opt;
    }
}

But the compiler doesn't like that. However, I _did_ get it working by doing this:

GetoptResult getopt(T...)(scope T opts) @safe
{
    return GetoptResult([Option(opts[0], opts[1])]);
}

Which is not ideal, obviously, but the notion that some code has to be rewritten to accomodate ownership semantics is not a new one; one of the major complaints I've seen about Rust is that it requires you to adjust your coding style to satisfy the borrow checker.

Reply via email to