[Dlang-study] [lifetime] [inout] Escape analysis through 'scope with owners'

Olivier FAURE olivier.faure at epitech.eu
Sun Jan 15 14:38:23 PST 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.


More information about the Dlang-study mailing list