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?