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?

Reply via email to