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

ag0aep6g anonymous at example.com
Mon Aug 31 05:46:45 UTC 2020


On 31.08.20 06:24, outlandkarasu wrote:
> I thought that I cannot make non-scope `ref` parameters from `scope` 
> array references.
> But I found It allowed currently.
[...]
> enum Currency : string {
>      USD = "USD", EUR = "EUR", GBP = "GBP", JPY = "JPY",
> }
> 
> struct Instrument {
>      Currency bid;
>      Currency ask;
> }
> 
> struct Price {
>      Instrument instrument;
>      ulong value;
> }
[...]
>      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;
>          }
>      }

`ref` kind of implies `scope` [1]. You don't need to type it out. When 
you do type out `scope ref const(Price)`, the `scope` actually doesn't 
apply to the `ref` but to the pointers in `Price` (whereas the `scope` 
in `scope const(Price)[]` applies to the pointer of the array).

So you don't need `scope` on the `price` parameter because you're taking 
it as a `ref`. You would need `scope` if you were taking it as a pointer 
(`scope const(Price)* price`).

By the way, semantically there isn't any reason to take `price` as 
either `ref` or pointer. You can just as well take it by value, since 
you're making a copy of it anyway with `minPrice = price` (and you also 
make a copy earlier with `foreach (price; prices)`).

[...]
> 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;
> }
> --------

Definitely a bug, yes. Reduced test case:

----
class MinPointerRecorder
{
     int* minPrice;
     void update(ref int price) @safe
     {
         minPrice = &price; /* Should not compile. */
     }
}

void main() @safe
{
     auto r = new MinPointerRecorder;
     () { int mp = 42; r.update(mp); } ();
     () { ulong[1000] stomp = 13; } ();
     import std.stdio: writeln;
     writeln(*r.minPrice); /* Prints "13". */
}
----

I don't think this is in Bugzilla yet. Please file an issue. Or let me 
know if you want me to do it.

https://issues.dlang.org




[1] I'm not exactly sure how it works. As far as I know, it's not 
documented anywhere.


More information about the Digitalmars-d-learn mailing list