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