digitalmars.D - Problem with Point property
- Henning Hasemann (33/33) Mar 06 2007 Hi all, say I have a structure Point and an attribute position like this...
- Hasan Aljudy (8/55) Mar 06 2007 If you return a pointer, you can still use the . operator, so I think
- Henning Hasemann (8/16) Mar 06 2007 Yeah, I tried this before, but got exactly the described Problem and
-
Chris Miller
(10/25)
Mar 06 2007
On Tue, 06 Mar 2007 16:29:14 -0500, Henning Hasemann
... - Henning Hasemann (8/15) Mar 06 2007 A first test lets me think, the compiler reads this as:
- Manfred Nowak (10/13) Mar 06 2007 The problem īseems to stem from the often used breaking of the data
- Henning Hasemann (13/25) Mar 07 2007 So you're saying one should better write a setPosition method instead of...
- Henning Hasemann (60/60) Mar 07 2007 I found a 'solution' myself which is aahh.. 'tricky'.
- Chris Nicholson-Sauls (5/76) Mar 07 2007 Actually, that's rather slick, and worth studying, even if it turns out ...
Hi all, say I have a structure Point and an attribute position like this: struct Point { int x, y; } class Foo { Point position; } So far, so good. Now I want to substitude the attribute with a property (because I want to react on changes of the position immediately) The setter is no Problem: void position(Point p) { mPosition = p; react(); } The getter indeed is. If I wrote: Point position() { return mPosition; } this would break expressions like Foo().position.x = 5; which I happen to use often. The solutions I see are * Return a proxy object instead of a real Point. Bad because the return type is not Point anymore. * Return a Point*, would break types too I dont know if these two even work. * Turn Point into a class so I return a reference. Possible, but Point really just carries 2 integers and I either had to change all "Point(...)"'s into "new Point(...)"'s, or implement opCall for a class which I'm not sure if it is the best option, since it may be misleading. Are there other ways? Can I somehow return a reference to a struct without "leaving" the type? What would you do? TIA, Henning -- v4sw7Yhw4ln0pr7Ock2/3ma7uLw5Xm0l6/7DGKi2e6t6ELNSTVXb7AHIMOen5a2Xs5Mr2g5ACPR hackerkey.com
Mar 06 2007
Henning Hasemann wrote:Hi all, say I have a structure Point and an attribute position like this: struct Point { int x, y; } class Foo { Point position; } So far, so good. Now I want to substitude the attribute with a property (because I want to react on changes of the position immediately) The setter is no Problem: void position(Point p) { mPosition = p; react(); } The getter indeed is. If I wrote: Point position() { return mPosition; } this would break expressions like Foo().position.x = 5; which I happen to use often. The solutions I see are * Return a proxy object instead of a real Point. Bad because the return type is not Point anymore. * Return a Point*, would break types too I dont know if these two even work. * Turn Point into a class so I return a reference. Possible, but Point really just carries 2 integers and I either had to change all "Point(...)"'s into "new Point(...)"'s, or implement opCall for a class which I'm not sure if it is the best option, since it may be misleading. Are there other ways? Can I somehow return a reference to a struct without "leaving" the type? What would you do? TIA, HenningIf you return a pointer, you can still use the . operator, so I think foo().point.x; should work just fine (both syntactically and semantically) However the implication is that if you have a function that takes a point struct object, you either have to change that function to take a point pointer, or dereference the property every time you pass it to functions.
Mar 06 2007
If you return a pointer, you can still use the . operator, so I think foo().point.x; should work just fine (both syntactically and semantically) However the implication is that if you have a function that takes a point struct object, you either have to change that function to take a point pointer, or dereference the property every time you pass it to functions.Yeah, I tried this before, but got exactly the described Problem and didnt wand to change my functions to receive Point* because that would seem strange and inconsistent. I'd have to use Point* everywhere maybe but then I could as well make Point a class I think. Henning -- v4sw7Yhw4ln0pr7Ock2/3ma7uLw5Xm0l6/7DGKi2e6t6ELNSTVXb7AHIMOen5a2Xs5Mr2g5ACPR hackerkey.com
Mar 06 2007
On Tue, 06 Mar 2007 16:29:14 -0500, Henning Hasemann <hhasemann web.de> = = wrote:Hi all, say I have a structure Point and an attribute position like th=is:struct Point { int x, y; } class Foo { Point position; } So far, so good. Now I want to substitude the attribute with a propert=y(because I want to react on changes of the position immediately) The setter is no Problem: void position(Point p) { mPosition =3D p; react(); } The getter indeed is. If I wrote: Point position() { return mPosition; } this would break expressions like Foo().position.x =3D 5;This should be easy enough for the compiler to detect and automatically = = call the matching setter (if none, error). But the compiler doesn't even= = detect some basic operators on properties, so...
Mar 06 2007
A first test lets me think, the compiler reads this as: Point tmp = (new Foo()).position; tmp.x = 5; speak: The position is copied from the object and the assignment is made on the copy. Henning -- v4sw7Yhw4ln0pr7Ock2/3ma7uLw5Xm0l6/7DGKi2e6t6ELNSTVXb7AHIMOen5a2Xs5Mr2g5ACPR hackerkey.comFoo().position.x = 5;This should be easy enough for the compiler to detect and automatically call the matching setter (if none, error). But the compiler doesn't even detect some basic operators on properties, so...
Mar 06 2007
Henning Hasemann wrotethis would break expressions like Foo().position.x = 5; which I happen to use often.The problem īseems to stem from the often used breaking of the data encapsulation in the class Foo. I already wrote about my _feeling_ that using properties as substitutes for field accesses is inherently wrong because it also breaks data encapsulation. Getters might be better seen as delegates, capable of answering questions about the state of the instance they stem from at that point in time when they were requested. -manfred
Mar 06 2007
The problem =B4seems to stem from the often used breaking of the data=20 encapsulation in the class Foo. =20 I already wrote about my _feeling_ that using properties as substitutes=20 for field accesses is inherently wrong because it also breaks data=20 encapsulation. =20 Getters might be better seen as delegates, capable of answering=20 questions about the state of the instance they stem from at that point=20 in time when they were requested. =20 -manfredSo you're saying one should better write a setPosition method instead of a setter? Or how would you make it? The semantic is, that Foo really has a position, but when it is changed, it should inform another object because that holds Foo's sorted by y-positi= on. But that in turn is an implementation detail, a user of Foo should not notice nor care about: Maybe later on I'll just resort the Foo's from time to time or when I need them sorted or whatever. Henning --=20 v4sw7Yhw4ln0pr7Ock2/3ma7uLw5Xm0l6/7DGKi2e6t6ELNSTVXb7AHIMOen5a2Xs5Mr2g5ACPR= hackerkey.com
Mar 07 2007
I found a 'solution' myself which is aahh.. 'tricky'. I extend the struct to be able to call the setter method whenever its value changes. To stop behaving it like a pointer, I misuse opCast as a 'copy constructor'. So Point p = (new Foo).position; p.x = 5; wont change the Foo's position, as it where when position was a real member. Look here: struct Point { private { int mX, mY; void delegate(Point) setter; } Point opCast() { Point p; p.setter = null; p.mX = x; p.mY = y; return p; } int x() { return mX; } void x(int x1) { mX = x1; if(setter !is null) setter(*this); } // skipped the same for y } To be used like: class Bar { private Point mPosition; this() { mPosition.setter = &position; } Point position() { return mPosition; } void position(Point p) { mPosition = p; } } Bar b; // This actually changes the object b.position.x = 7; writefln(b.position.x); // 7 // This as before, does not Point p = b.position; // here opCast is being called p.x = 5; writefln(b.position.x); // still 7 The only thing is Im not quite sure if using opCast this way is portable across versions and compiler manufracturers, anyone knowing something about that? Henning -- v4sw7Yhw4ln0pr7Ock2/3ma7uLw5Xm0l6/7DGKi2e6t6ELNSTVXb7AHIMOen5a2Xs5Mr2g5ACPR hackerkey.com
Mar 07 2007
Henning Hasemann wrote:I found a 'solution' myself which is aahh.. 'tricky'. I extend the struct to be able to call the setter method whenever its value changes. To stop behaving it like a pointer, I misuse opCast as a 'copy constructor'. So Point p = (new Foo).position; p.x = 5; wont change the Foo's position, as it where when position was a real member. Look here: struct Point { private { int mX, mY; void delegate(Point) setter; } Point opCast() { Point p; p.setter = null; p.mX = x; p.mY = y; return p; } int x() { return mX; } void x(int x1) { mX = x1; if(setter !is null) setter(*this); } // skipped the same for y } To be used like: class Bar { private Point mPosition; this() { mPosition.setter = &position; } Point position() { return mPosition; } void position(Point p) { mPosition = p; } } Bar b; // This actually changes the object b.position.x = 7; writefln(b.position.x); // 7 // This as before, does not Point p = b.position; // here opCast is being called p.x = 5; writefln(b.position.x); // still 7 The only thing is Im not quite sure if using opCast this way is portable across versions and compiler manufracturers, anyone knowing something about that? HenningActually, that's rather slick, and worth studying, even if it turns out not to be optimal. (Which with a significant number of such properties, it couldn't possibly be.) I really can't offer anything better off hand. -- Chris Nicholson-Sauls
Mar 07 2007