January 15, 2017
I think there have been a lot of discussion and propositions about escape analysis, GC, RC, and DIP 1000. Since I've been thinking about those for a while, I'd like to add my ideas to the mix.

First off, I don't really like DIP1000 or DIP25. I think the 'return scope' parameter attribute lacks elegance in a way similar to inout attribute, and is likely to follow the same dynamic if implemented: solve the most obvious problems in a neat way, but create a never-ending stream of little imperfections that slowly amass, and end up needing to be redone from the ground up.

Also, while it solves the "@safe identity" problem, it doesn't solve cases where you might want to store a scope parameter in an out parameter, or swap two scope parameters, which should logically be possible to do safely.

I think Schuetzm's original proposition (http://wiki.dlang.org/User:Schuetzm/scope) should be re-examined, and would be more beneficial to the D language in the long term.

The gist of it is, variables can be declared scope (this is already the case), but can also declared to be "as scoped as another variable". The canonical example is the find function function:

    scope!haystack(string) findSubstring(scope(string) haystack, scope(string) needle);

Or, with a little inference from the compiler:

    scope!haystack(string) findSubstring(string haystack, string needle) @pure;

My main thought on the subject is that scope shouldn't be a storage class, it should be a non-binary type qualifier. That is, in the following example:

    int foobar()
    {
        int* x;

        myLabel:
        {
           scope int* y;
        }
    }

x is not 'scope(false) int*' and y is not 'scope(true) int*'; rather, x would be 'scope!null int*' and y would be 'scope!myLabel int*'. Thus, checking whether an assignation is possible would be a matter of comparing both types; which would allow more advanced possibilities like:

    int foobar()
    {
        scope int* x;

        myLabel:
        {
           scope!foobar int* y;
           ...
           x = y;
        }

        myLabel2:
        {
           scope!(myLabel2, foobar) int* y; // equivalent to scope!foobar
           scope!(myLabel, myLabel2) int* z; // ERROR: No overlap between both scopes
        }
    }

For functions which need to pass scope as a parameter, the scope of any given variable would actually be a set:

void swap(T)(ref scope!arg2 T arg1, ref scope!arg1 T arg2)
{
    auto tmp = arg1;

    arg2 = arg1;
    arg1 = tmp;
}

Here, the scope of tmp would be something like {swap & arg1 & arg2}. It could only be assigned to a variable with a scope equal or containing this, hence why arg1 and arg2 have to be marked as scope!theOtherOne.

I have other thoughts, and I'm thinking about making a DIP, but first I'd like to know what the community thinks. Schuetzm's original proposal seems to have been more or less forgotten, and hasn't come up in the discussions about DIP1000; I don't know what the reason is, but I do think it deserves more attention.
_______________________________________________
Dlang-study mailing list
Dlang-study@puremagic.com
http://lists.puremagic.com/cgi-bin/mailman/listinfo/dlang-study