www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - opOpAssign on object properties

reply collerblade <collerblade gmail.com> writes:
hello guys,
i would like to have properties with /= *= += -= operators. My 
code:

struct Point {
   float x=0,y=0;

   this(float _x, float _y) {
     x=_x;
     y=_y;
   }

   //opassign for +

   //opopassign for +=
   void opOpAssign(string op=="+")(in Point p) {
     x+=p.x;
     y+=p.y;
   }
}

class A {
   public:
     Point location() const  property {
       return m_location;
     }

     void location(in Point newlocation)  property {
       m_location=newlocation;
     }

   private:
     Point m_location;
}

void main() {
   auto a= new A;
   a.location=a.location+Point(1,1); //DOES WORK
   a.location+=Point(1,1); //DOESN'T WORK
}



The problem is that this code is not working. The getter and the 
opOpAssign gets called, but the setter does not.
How can i do opOpAssign with properties??
Jan 08
parent reply Ivan Kazmenko <gassa mail.ru> writes:
On Sunday, 8 January 2017 at 09:22:12 UTC, collerblade wrote:
 How can i do opOpAssign with properties??
1. If you want the member variable to change, naturally, you should provide a getter property which returns a reference to that variable: ref Point location() property { return m_location; } This alone solves the immediate problem. 2. Note that it is common for assignment expressions to return a reference to the result, which would, for example, make chains like "a = (b += c)" possible: ref Point opOpAssign(string op)(in Point p) if (op == "+") { x+=p.x; y+=p.y; return this; } Here's a complete working version of your example: ----- struct Point { float x=0,y=0; this(float _x, float _y) { x=_x; y=_y; } //opopassign for += ref Point opOpAssign(string op)(in Point p) if (op == "+") { x+=p.x; y+=p.y; return this; } } class A { public: ref Point location() property { return m_location; } void location(in Point newlocation) property { m_location=newlocation; } private: Point m_location; } void main() { import std.stdio; auto a= new A; a.location+=Point(1,1); writeln (a.location); // Point(1, 1) a.location+=Point(1,1); writeln (a.location); // Point(2, 2) } ----- Ivan Kazmenko.
Jan 08
parent reply collerblade <collerblade gmail.com> writes:
On Sunday, 8 January 2017 at 10:03:50 UTC, Ivan Kazmenko wrote:
 On Sunday, 8 January 2017 at 09:22:12 UTC, collerblade wrote:
 [...]
1. If you want the member variable to change, naturally, you should provide a getter property which returns a reference to that variable: [...]
yes i tried the reference return, but the problem is, that the setter does NOT gets called, no matter what the result type of the opOpAssign method is. I want to detect changes, but this way i still not able. A a = new A; a.location+=Point(1,1); //the private value changes, but the setter does not get called
Jan 08
parent reply Ivan Kazmenko <gassa mail.ru> writes:
On Sunday, 8 January 2017 at 18:23:34 UTC, collerblade wrote:
 On Sunday, 8 January 2017 at 10:03:50 UTC, Ivan Kazmenko wrote:
 On Sunday, 8 January 2017 at 09:22:12 UTC, collerblade wrote:
 [...]
1. If you want the member variable to change, naturally, you should provide a getter property which returns a reference to that variable: [...]
yes i tried the reference return, but the problem is, that the setter does NOT gets called, no matter what the result type of the opOpAssign method is. I want to detect changes, but this way i still not able. A a = new A; a.location+=Point(1,1); //the private value changes, but the setter does not get called
Hmm, right. The setter is not called, and it's by the spec. Which says that "a op= b" is rewritten as "a.opOpAssign !(op) (b)". Here: https://dlang.org/spec/operatoroverloading.html#op-assign So, no *assignment* happens when you call a.location+=Point(1,1). To have a side effect triggered by opAssign-ment, you can do it inside the opOpAssign function. Looking at it another way, actions with struct Point can be seen as the responsibility of struct Point. If you want to monitor these actions, do it in the code of opOpAssign function. After that, your class A can inspect the state of its corresponding Point. If normal Points don't need that, you can have a special SelfAwarePoint which has an alias this to its member Point. Alternatively, you can have two getter properties: one as const and one by reference. When the reference one gets called, you know the value of Point *may* have changed. Well, I'm out of ideas for now. If these still don't quite satisfy you, including a bigger picture of what you want to achieve may help. Ivan Kazmenko.
Jan 08
parent collerblade <collerblade gmail.com> writes:
On Sunday, 8 January 2017 at 21:50:12 UTC, Ivan Kazmenko wrote:
 On Sunday, 8 January 2017 at 18:23:34 UTC, collerblade wrote:
 [...]
Hmm, right. The setter is not called, and it's by the spec. Which says that "a op= b" is rewritten as "a.opOpAssign !(op) (b)". Here: https://dlang.org/spec/operatoroverloading.html#op-assign [...]
Y, i have came up the same conclusion. I have to place an event like system into the Point. Ty
Jan 08