Thread overview | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
March 06, 2007 Problem with Point property | ||||
---|---|---|---|---|
| ||||
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
|
March 06, 2007 Re: Problem with Point property | ||||
---|---|---|---|---|
| ||||
Posted in reply to Henning Hasemann | 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,
> Henning
>
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.
|
March 06, 2007 Re: Problem with Point property | ||||
---|---|---|---|---|
| ||||
Posted in reply to Henning Hasemann | 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 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;
>
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...
|
March 06, 2007 Re: Problem with Point property | ||||
---|---|---|---|---|
| ||||
Posted in reply to Hasan Aljudy | > 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 |
March 06, 2007 Re: Problem with Point property | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris Miller | > > > > Foo().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... 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.com |
March 06, 2007 Re: Problem with Point property | ||||
---|---|---|---|---|
| ||||
Posted in reply to Henning Hasemann | Henning Hasemann wrote
> this 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
|
March 07, 2007 Re: Problem with Point property | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manfred Nowak | > 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 So 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-position. 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 -- v4sw7Yhw4ln0pr7Ock2/3ma7uLw5Xm0l6/7DGKi2e6t6ELNSTVXb7AHIMOen5a2Xs5Mr2g5ACPR hackerkey.com |
March 07, 2007 Re: Problem with Point property | ||||
---|---|---|---|---|
| ||||
Posted in reply to Henning Hasemann |
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
|
March 07, 2007 Re: Problem with Point property | ||||
---|---|---|---|---|
| ||||
Posted in reply to Henning Hasemann | 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?
>
> Henning
>
Actually, 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
|
Copyright © 1999-2021 by the D Language Foundation