How do I copy struct having immutable pointer member when enabled DIP1000?

outlandkarasu outland.karasu at gmail.com
Mon Aug 31 04:24:50 UTC 2020


On Sunday, 30 August 2020 at 16:33:58 UTC, ag0aep6g wrote:
> On 30.08.20 17:24, outlandkarasu wrote:
>> --------
>> enum Tag { tag = "tag" }
>> 
>> struct A { Tag tag; }
>> 
>> A createA() @safe
>> {
>>      scope a = A(Tag.tag);
>> 
>>      // Error: scope variable a may not be returned
>>      return a;
>> 
>>      // NG
>>      // return A(a);
>>      // return A(a.tag);
>> }
>> --------
> [...]
>> I understand those errors are DIP1000 language design.
>> However I suppose that DIP1000 check can permit immutable 
>> pointer in some cases.
>
> If I understand correctly, your point is that an enum pointer 
> is guaranteed to refer to static data, so it could be exempt 
> from `scope` checks.
>
> At a glance, that makes sense to me. But I guess one question 
> is whether it's possible to create an enum value that points to 
> the stack. A cast does the trick:
>
>     immutable char[1] c = 'e';
>     E e = cast(E) c[];
>
> DMD accepts it as @safe, implying that the cast is valid and 
> that `e` is a safe value. If that is correct, then enum 
> pointers are actually not guaranteed to refer to static data. 
> They can just as well point to the stack. Consequently, an enum 
> pointer must be treated like a plain pointer. I.e., `scope` 
> must treat a `Tag` just like a plain `string`.
>
>> Is there a better workaround, practices or patterns?
>
> In your example, you can just remove the `scope` annotation. 
> Why mark a local that you want to return with `scope`? Doesn't 
> make sense
>
> But I guess your actual use case isn't as simple. Maybe you can 
> show a less reduced version of the code where simply removing 
> `scope` is not an option?

Thanks for your reply.

I thought that I cannot make non-scope `ref` parameters from 
`scope` array references.
But I found It allowed currently.

My reduced version code is below;

--------
enum Currency : string {
     USD = "USD", EUR = "EUR", GBP = "GBP", JPY = "JPY",
}

struct Instrument {
     Currency bid;
     Currency ask;
}

struct Price {
     Instrument instrument;
     ulong value;
}

class MinRecorder
{
@nogc nothrow pure @safe:

     // prices from local scoped array buffers.
     // I want to restrict prices reference to scope.
     void update(scope const(Price)[] prices) scope
     {
         foreach (price; prices)
         {
             update(price);
         }
     }

     // I thought price parameter need `scope` when called by 
scoped array elements.
     // But it can remove `scope` attribute.
     void update( /* scope */ ref const(Price) price) scope
     {
         if (minPrice.isNull || price.value < minPrice.get.value)
         {
             minPrice = price;
         }
     }

     Nullable!Price minPrice;
}
--------

full example:
https://run.dlang.io/is/wVbrwf

I also found a worried point that I can take non-scope pointer 
from non-scope `ref` parameter in DMV v2.093.1.

--------
class MinPointerRecorder
{
@nogc nothrow pure @safe:

     void update(scope const(Price)[] prices) scope
     {
         foreach (price; prices)
         {
             update(price);
         }
     }

     void update( /* scope */ ref const(Price) price) scope
     {
         if (!minPrice || price.value < minPrice.value)
         {
             // Is this DIP1000 BUG?
             // When without DIP1000, reported compile error.
             // Error: cannot take address of parameter price
             minPrice = &price;
         }
     }

     const(Price)* minPrice;
}
--------

I also think about Flyweight pattern in D.
I expected simple struct that contains cached `immutable` 
reference behaves a simple value type like primitive types.
But reference contained struct is not simple.

If I want a simple value type struct, the struct shouldn't be 
contain any references also include static string or immutable 
reference.


More information about the Digitalmars-d-learn mailing list