RFC: scope and borrowing

via Digitalmars-d digitalmars-d at puremagic.com
Thu Oct 23 12:20:11 PDT 2014


On Saturday, 4 October 2014 at 19:26:01 UTC, Marc Schütz wrote:
> On Saturday, 4 October 2014 at 19:22:45 UTC, Marc Schütz wrote:
>> On Saturday, 4 October 2014 at 18:13:03 UTC, Ivan Timokhin 
>> wrote:
>>> Also, would it really make much sense to track the owner 
>>> further than the assignment of a function's return value? 
>>> That seems to complicate things a lot by adding a hidden 
>>> attribute to a variable that is not only invisible at the 
>>> declaration (even though the full type is spelled out), but, 
>>> in fact, cannot be specified explicitly (because there's no 
>>> syntax for that, now that scope with owners is limited to 
>>> function signatures).
>>>
>>> How about this:
>>> ---
>>>   scope(string) haystack, needle;
>>>   // next assignment is okay, because `s` is guaranteed not 
>>> to outlive
>>>   // `haystack`.
>>>   scope(string) s = findSubstring(haystack, needle);
>>>   // type of `s` is now scope(string), no additional 
>>> information
>>>   // attached
>>>
>>>   // so the next assignment is disallowed:
>>>   //needle = s; // error!
>>> ---
>>>
>>> This could be unnecessarily limiting, but would it really 
>>> cause much trouble?
>>
>> I think you're right, I thought about this after I replied to 
>> you. It would be the logical next step. On the other hand, I 
>> wouldn't want to lose const borrowing, because it turned out 
>> to be a requirement for safe moving. But I think it can still 
>> be tracked internally (owner tracking is necessary for 
>> implementation anyway).
>
> Owner tracking is then completely limited to one expression. I 
> think this will simplify the implementation a lot. Besides, it 
> has precedences: uniqueness is also only tracked inside an 
> expression, AFAIK.

... and value range propagation.

I've worked in the changes talked about so far, and I think I've 
found a practicable solution for the forwarding problem. The idea 
is to make the owner constraints (i.e. the things we declare in 
function signatures) part of the type, but make types that only 
differ in their constraints equivalent. This avoids template 
bloat, but allows them to be forwarded where necessary. This is 
at the cost of needing to spread this information outwards when a 
template is going to be instantiated, which is however doable and 
inexpensive, as the compiler needs to do a full analysis of the 
template body anyway:

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

     auto trace(alias func, Args...)(Args args) {
         import std.conv : to;
         writeln("Calling " ~ func.stringof ~
                 "(" ~ args.to!string ~ ")");
         return func(args);
     }

     auto s = trace!findSubstring(haystack, needle);

     // expands to:
     scope!haystack(string) trace_findSubstring(
         scope(string) haystack,
         scope(string) needle
     ) {
         import std.conv : to;
         writeln("Calling findSubstring(" ~
                 args.to!string ~ ")");
         return findSubstring(args);
     }

Full proposal is here:
http://wiki.dlang.org/User:Schuetzm/scope


More information about the Digitalmars-d mailing list