Thread overview
Return value storage classes - `scope` as well as `ref`
May 29, 2023
Nick Treleaven
May 30, 2023
Dukc
May 30, 2023
Dukc
May 31, 2023
Nick Treleaven
May 31, 2023
Nick Treleaven
May 30, 2023
Quirin Schroll
May 29, 2023

Recently we've discussed syntax solutions to ref not applying to a variable/parameter when those are of function pointer type:
https://issues.dlang.org/show_bug.cgi?id=2753

ref is a function attribute, so this problem is easier to solve. Also it is not allowed after the parameter list because conceptually it applies to the return value.

However, there is another case of missing syntax for an unimplemented feature. scope would be useful to apply to the return value of a function. Currently scope is disallowed on functions except for methods or delegates, where it applies to this or the context. There are cases where it would be useful to apply to the return value - e.g. for List.front here:
https://issues.dlang.org/show_bug.cgi?id=17934

    Elem elem;
    {
        auto l = list();
        elem = l.front; // should error
        // destructor called
    }

And for S.fp here:
https://forum.dlang.org/post/mqyqlieghqwsinbqiqbp@forum.dlang.org

    int* p;
    {
        auto lf = S(5);
        p = lf.fp; // should error
        // destructor called
    }

Syntax solutions proposed to fix the ref problem are:

The first two have PRs. I think only the latter fixes the scope problem. A simpler fix would be this ordering:

Type ReturnStorage? Identifier Parameters

Where ReturnStorage is ref or scope.

T scope ref func_name();

Using parentheses just for the storage class(es) would work too:

(scope ref) T func_name();

Also, solving the problem generally could be useful in the future if we want any other storage classes to apply to the return value rather than the function or the parameter.

May 30, 2023

On Monday, 29 May 2023 at 10:08:38 UTC, Nick Treleaven wrote:

>

And for S.fp here:
https://forum.dlang.org/post/mqyqlieghqwsinbqiqbp@forum.dlang.org

    int* p;
    {
        auto lf = S(5);
        p = lf.fp; // should error
        // destructor called
    }

No, this is working just as it should. lf is not scope, so a return value of a return scope function should be neither.

Maybe you're confusing lifetime of struct itself with lifetime of what it's pointing to. return scope return value is scope only if the struct is scope - that is, potentially pointing to a local with one or more of it's fields. Whether the struct itself is in stack is irrelevant.

On the other hand, return (without the trailing scope, return ref when applied to a parameter) means the return value is scope if the struct is in a stack. Maybe that's what you intended S.fp to be.

May 30, 2023

On Tuesday, 30 May 2023 at 07:21:44 UTC, Dukc wrote:

>

No, this is working just as it should. lf is not scope, so a return value of a return scope function should be neither.

Oh sorry, didn't read your whole post. You weren't claiming there's a bug but suggesting a new design. That is, making lf be scope with this syntax.

I still prefer the current solution, though. scope is an on/off attribute only from perspect of variables. Expression, though, have shortest possible lifetimes, meaning they figure out which local scope the result is guaranteed to last. S(5) is an expression, so the compiler needs to figure out it's shortest possible lifetime even if it isn't immediately assigned to a variable. What should it be? It isn't obvious.

What does work, without language changes, is giving a sentinel pointer parameter to the constructor that is used to figure out the shortest possible lifetime. That is, the constructor is defined this(int, return scope void* sentinel) and is used S(5, &localVariableIWontOutlive).

May 30, 2023

On Monday, 29 May 2023 at 10:08:38 UTC, Nick Treleaven wrote:

>

However, there is another case of missing syntax for an unimplemented feature. scope would be useful to apply to the return value of a function.

By “unimplemented feature” are you suggesting a new langue feature or is there something specified that is not implemented yet?

If it’s already in the spec, please quote the relevant sections.

May 31, 2023

On Tuesday, 30 May 2023 at 07:21:44 UTC, Dukc wrote:

>

On the other hand, return (without the trailing scope, return ref when applied to a parameter) means the return value is scope if the struct is in a stack. Maybe that's what you intended S.fp to be.

Yes, thanks I didn't know that. I'm not sure if that's documented anywhere in the spec.
https://dlang.org/spec/function.html#return-scope-parameters

This also resolves the bugzilla issue:
https://issues.dlang.org/show_bug.cgi?id=17934#c12

May 31, 2023

On Wednesday, 31 May 2023 at 10:29:06 UTC, Nick Treleaven wrote:

>

I'm not sure if that's documented anywhere in the spec.

https://github.com/dlang/dlang.org/pull/3619