[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