Passing a reference to a returned reference

Michael michael at toohuman.io
Fri Jul 6 15:51:34 UTC 2018


On Friday, 6 July 2018 at 15:37:25 UTC, Timoses wrote:
> On Friday, 6 July 2018 at 15:14:01 UTC, Michael wrote:
>> class Agent
>> {
>>     private
>>     {
>>         double[int] mDict;
>>     }
>>
>>     // Setter: copy
>>     void beliefs(ref double[int] dict)
>>     {
>>         import std.stdio : writeln;
>>         writeln("Setter function.");
>>         this.mDict = dict;
>>     }
>>
>>     // Getter
>>     auto ref beliefs()
>>     {
>>         return this.mDict;
>>     }
>> }
>>
>> class Operator
>> {
>>     static auto ref create()
>>     {
>>         double[int] dict;
>>         dict[2] = 1.0;
>>         dict[1] = 0.0;
>>         return dict;
>>     }
>> }
>
> Throw in a writeln statement in getter and be amazed : D
>
>     class Agent
>     {
>         private
>         {
>             double[int] mDict;
>         }
>
>         // Setter: copy
>         void beliefs(ref double[int] dict)
>         {
>             import std.stdio : writeln;
>             writeln("Setter function.");
>             this.mDict = dict;
>         }
>
>         // Getter
>         auto ref beliefs()
>         {
>             writeln("getter");
>             return this.mDict;
>         }
>     }
>
>     class Operator
>     {
>         static auto ref create()
>         {
>             double[int] dict;
>             dict[2] = 1.0;
>             dict[1] = 0.0;
>             return dict;
>         }
>     }
>
>     unittest
>     {
>         import std.stdio : writeln;
>
>         Agent a = new Agent();
>
>         writeln("Statement 1");
>         a.beliefs = Operator.create();
>         writeln("Statement 2");
>         assert(a.beliefs.keys.length == 2);
>
>         writeln("Statement 3");
>         writeln(a.beliefs);
>     }
>
> If you remove the ref then "Statement 1" will use the setter 
> method. Otherwise it calls the "auto ref" function to get a 
> reference of 'mDict' and assign it a value. Essentially
>
>         // Getter
>         auto ref beliefs()
>         {
>             return this.mDict;
>         }
>
> makes your "private" variable not private any more, since you 
> are leaking a reference to it. So any program calling 
> "a.beliefs" can get a reference to your private data and modify 
> it.
>
> My guess is that (if ref is removed from the setter) it serves 
> as a @property function:
> https://dlang.org/spec/function.html#property-functions
> So this allows the function to work in a statement like:
> a.beliefs = <Whatever>
>
> And apparently it is prioritized over the "ref beliefs()" 
> function.
>
>
> I guess it is nicer to actually use the "setter" function, as 
> it allows you to inspect what the private data will be assigned 
> to and take appropriate measures, whereas with the "ref 
> beliefs()" method the private data is open for any manipulation 
> out of your control.

How strange! Nice find though, thanks for your help with this, I 
really appreciate it as this had been bugging me for a while.

So essentially, what is happening is, if the setter method 
expects a reference, then because the create() function isn't 
returning a reference but a copy, it actually does the following:

a.beliefs = Operator.create();

receives an object from create(), while a.beliefs retrieves a 
reference to agent.mBeliefs, and then effectively sets this 
reference to point to the object copied by create()?

Also, yes, I am using the setter method to play around with the 
precision of the double values, and do some normalising. I always 
want it to access the setter method, but I had hoped that, given 
it's an associative array, that the creation of the object in 
create() would simply create it on the heap and I could pass back 
a reference. It seems that I was incorrect, as if I set create() 
to explicitly return a reference, it complains about returning a 
reference to a local variable. Any advice on the best way to pass 
it as a reference?


More information about the Digitalmars-d-learn mailing list