DIP69 - Implement scope for escape proof references

Walter Bright via Digitalmars-d digitalmars-d at puremagic.com
Sat Dec 6 14:56:07 PST 2014


On 12/6/2014 5:30 AM, "Marc Schütz" <schuetzm at gmx.net>" wrote:
> On Friday, 5 December 2014 at 23:58:41 UTC, Walter Bright wrote:
>> As you point out, 'ref' is designed for this.
> I wouldn't call it "designed", but "repurposed"...

Perhaps, but the original reason to even have 'ref' was so it could be a 
restricted pointer type that could be passed down a call hierarchy, but not up.


>
>>>     struct Container(T) {
>>>         scope ref T opIndex(size_t index);
>>>     }
>>>
>>>     void bar(scope ref int a);
>>>
>>>     Container c;
>>>     bar(c[42]);            // ok
>>>     scope ref tmp = c[42]; // nope
>>>
>>> Both cases should be fine theoretically; the "real" owner lives longer than
>>> `tmp`. Unfortunately the compiler doesn't know about this.
>>
>> Right, though the compiler can optimize to produce the equivalent.
>
> ??? This is a problem on the semantic level, unrelated to optimization:
>
>      // contrived example to illustrated the point
>      Container c;
>      scope ref x = c[42];   // not
>      scope ref y = c[44];   // ...
>      scope ref z = c[13];   // allowed
>      foo(x, y, z, x+y, y+z, z+x, x+y+z);
>
>      // workaround, but error-prone and has different semantics
>      // (opIndex may have side effects, called multiple times)
>      foo(c[42], c[44], c[13], c[42]+c[44], c[44]+c[13], c[13]+c[42],
> c[42]+c[44]+c[13]);
>
>      // another workaround, same semantics, but ugly and unreadable
>      (scope ref int x, scope ref int y, scope ref int z) {
>          foo(x, y, z, x+y, y+z, z+x, x+y+z);
>      }(c[42], c[44], c[13]);

You are correct, and it remains to be seen if these occur enough to be a problem 
or not. The workarounds do exist, though. Another workaround:

     scope ref tmp = c[42];

becomes:

     auto scope ref tmp() { return c[42]; }


> Ok, so let's drop bar2() and bar4().
>
>      scope ref int foo();
>      scope ref int bar1(ref int a) {
>          return a;
>      }
>      ref int bar3(ref int a) {
>          return a;
>      }
>      ref int baz_noscope(/*scope*/ ref int a);
>
>      foo().bar1().baz_noscope();
>      foo().bar3().baz_noscope();
>
> And now? In particular, will the return value of `bar3` be treated as if it were
> `scope ref`?

Yes.



More information about the Digitalmars-d mailing list