Why can't I give a function's return type the scope storage class?

ag0aep6g anonymous at example.com
Tue Mar 19 16:11:27 UTC 2019


On 19.03.19 04:48, Meta wrote:
> My example code is a bit too long to post here, but it can be found at 
> https://run.dlang.io/is/e6Lc15. The main crux of this issue is:
> 
> @safe
> Queue!Data copyToQueue(DataRange data)
> {
>      Queue!Data output;
>      while (!data.empty)
>      {
>          auto d = data.front;
>          data.popFront();
>          import std.random: uniform;
>          if (uniform(0, 100) < 50)
>          {
>              output.push(d);
>          }
>      }
>      return output;
> }
> 
> And the definition of Queue!T.push is:
> 
>      @safe
>      void push(return scope T val) scope
>      {
>          ptr += 1;
>          if (ptr >= store.length && ptr < size_t.max)
>          {
>              store.length = store.length == 0
>                  ? 8
>                  : store.length * growthFactor;
>          }
>          //FIXME: either I don't understand DIP1000
>          //well enough, or this should compile
>          //Workaround: surround it with an @trusted lambda
>          store[ptr] = val;
>      }

I think it boils down to the following.

This works:

     struct Q
     {
         string s;
         void push(return scope string v) scope @safe
         {
             this.s = v;
         }
     }

This doesn't:

     struct Q
     {
         string[] s;
         void push(return scope string v) scope @safe
         {
             this.s.length = this.s.length + 1;
             this.s[$ - 1] = v;
         }
     }

The reason is that `scope` is not transitive. The array `this.s` is 
`scope`, but an element like `this.s[$ - 1]` isn't. The compiler 
considers the elements to have infinite lifetime.

Here's another example that illustrates this. When you've got a `scope 
Q`, the compiler won't let you return `q.s`, but it doesn't mind you 
returning an element of it:

     struct Q
     {
         string[] s;
     }
     string[] f(scope Q q)
     {
         return q.s; /* Error: scope variable q may not be returned */
     }
     string g(scope Q q)
     {
         return q.s[0]; /* no error, the element is not `scope` */
     }



More information about the Digitalmars-d mailing list