digitalmars.D - Abnormal struct properties behaviour
- nail (40/40) Dec 20 2004 Hi all.
- Lionello Lunesu (8/20) Dec 20 2004 Hi.
- =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= (4/11) Dec 20 2004 Until D gets C++-like references, structs won't work for properties...
- nail (7/18) Dec 20 2004 I don't want a reference for eye. I want double call of property setter ...
- David Medlock (12/22) Dec 20 2004 Have you measured the performance issues? I am doing exactly this sort
- Ben Hinkle (17/66) Dec 20 2004 There are some other options besides making language changes:
- nail (8/73) Dec 20 2004 "do something more" hides the following, for example:
- Ben Hinkle (34/38) Dec 20 2004 5
- pragma (18/22) Dec 20 2004 Pointers aren't preferred in D (they're ugly), but they do exist for rea...
- nail (1/9) Dec 20 2004 Maybe yo're right. The time will show.
Hi all. Consider following situation. We have a struct named Vector3 it has members public x, y and z. Also we have a class Camera that has property, for example, eye. The code is something like this: struct Vector3 { float x, y, z; ... } class Camera { protected Vector3 _eye; public void eye(Vector3 v) { _eye = v; // do something more } public Vector3 eye() { return _eye; } } void main() { Camera cam = new Camera(); cam.eye.y = 5; // dead line } In the code above "dead line" leads to changing y of the copy of the eye. I think this is not desired behaviour. Something must be done to correct this language behaviour. I don't know what is the best solution, but the following IMHO should work: If we write-access members/props of the struct returned by property then for writing second, write-property, must be called with parameter that is the changed copy of the read-property. ahem... I think I explain too complicately :). In another words, in the example above: 1) cam.eye() returns a copy of original vector _eye 2) 'y' component of this copy is changed to 5 3) write-property came.eye(Vector3) must be called with parameter obtained in previous action. Comments?
Dec 20 2004
Hi. "nail" <nail_member pathlink.com> wrote in message news:cq6h3c$1tj$1 digitaldaemon.com...[...] public Vector3 eye() { return _eye; } } void main() { Camera cam = new Camera(); cam.eye.y = 5; // dead line } In the code above "dead line" leads to changing y of the copy of the eye.Check the other thread in this newsgroup about "inout return values". I guess you'd want something like "inout Vector3 eye() { return eye; }" which would return a C++-like reference to the struct, instead of a copy. ....This is not yet possible, by the way :-S L.
Dec 20 2004
nail wrote:Consider following situation. We have a struct named Vector3 it has members public x, y and z. Also we have a class Camera that has property, for example, eye. In the code above "dead line" leads to changing y of the copy of the eye. I think this is not desired behaviour. Something must be done to correct this language behaviour.Until D gets C++-like references, structs won't work for properties... You need to either make Vector3 a class, or x/y/z into Camera fields ? --anders
Dec 20 2004
In article <cq6ivh$3rt$1 digitaldaemon.com>, =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= says...nail wrote:I don't want a reference for eye. I want double call of property setter / getter. First I get a property, then I change it, then I set property with additional operations coded in eye(Vector3 v)Consider following situation. We have a struct named Vector3 it has members public x, y and z. Also we have a class Camera that has property, for example, eye. In the code above "dead line" leads to changing y of the copy of the eye. I think this is not desired behaviour. Something must be done to correct this language behaviour.Until D gets C++-like references, structs won't work for properties...You need to either make Vector3 a class, or x/y/z into Camera fields ?First is impossible because of performance issues. Second is very annoying for example if I'd have not 3 members but 103.--anders
Dec 20 2004
nail wrote:Have you measured the performance issues? I am doing exactly this sort of coding and I see very small differences in struct/vs class ( at least compared to other parts of my code which use up more time). Typically I have 2 needs for Vectors/Points: 1. Equations such as what you posted, these are typically a minute portion of your running time. 2. Groups of them such as 3d Models where large quantities need to be manipulated. handles mass changes to the data and using vertex Arrays easy. Just my $0.02.You need to either make Vector3 a class, or x/y/z into Camera fields ?First is impossible because of performance issues. Second is very annoying for example if I'd have not 3 members but 103.--anders
Dec 20 2004
nail wrote:Hi all. Consider following situation. We have a struct named Vector3 it has members public x, y and z. Also we have a class Camera that has property, for example, eye. The code is something like this: struct Vector3 { float x, y, z; ... } class Camera { protected Vector3 _eye; public void eye(Vector3 v) { _eye = v; // do something more } public Vector3 eye() { return _eye; } } void main() { Camera cam = new Camera(); cam.eye.y = 5; // dead line } In the code above "dead line" leads to changing y of the copy of the eye. I think this is not desired behaviour. Something must be done to correct this language behaviour. I don't know what is the best solution, but the following IMHO should work: If we write-access members/props of the struct returned by property then for writing second, write-property, must be called with parameter that is the changed copy of the read-property. ahem... I think I explain too complicately :). In another words, in the example above: 1) cam.eye() returns a copy of original vector _eye 2) 'y' component of this copy is changed to 5 3) write-property came.eye(Vector3) must be called with parameter obtained in previous action. Comments?There are some other options besides making language changes: 1) it seems like you want your class to "do something more" when the entire eye is set but not when just the y component is set. This seems odd to me so I assume it is an artifact of shortening the example for posting. So my first reaction is the current behavior is avoiding a bug in your code. 2) returning a pointer from eye() isn't too bad and makes it obvious it is a reference. The line cam.eye.y would then change the copy owned by the Camera. But as I said in 1 this seems like it seems like that opens up a hole to change _eye without doing something more. 3) add properties to just set or translate one component of eye at a time. For example void eyeY(float new_y) { _eye.y = new_y; //do something more } Then instead of cam.eye.y = 5 you have cam.eyeY = 5. 4) don't do anything and just leave the eye setter as the only way to change _eye. I don't think users will be confused by the behavior of cam.eye.y = 5 -Ben
Dec 20 2004
In article <cq6kee$59v$1 digitaldaemon.com>, Ben Hinkle says...nail wrote:"do something more" hides the following, for example: renderSystem.SetViewMatrix( Matrix44.lookAt(_eye, _target, _up) ); you can see that it is necessary to be called even if one component changed.Hi all. Consider following situation. We have a struct named Vector3 it has members public x, y and z. Also we have a class Camera that has property, for example, eye. The code is something like this: struct Vector3 { float x, y, z; ... } class Camera { protected Vector3 _eye; public void eye(Vector3 v) { _eye = v; // do something more } public Vector3 eye() { return _eye; } } void main() { Camera cam = new Camera(); cam.eye.y = 5; // dead line } In the code above "dead line" leads to changing y of the copy of the eye. I think this is not desired behaviour. Something must be done to correct this language behaviour. I don't know what is the best solution, but the following IMHO should work: If we write-access members/props of the struct returned by property then for writing second, write-property, must be called with parameter that is the changed copy of the read-property. ahem... I think I explain too complicately :). In another words, in the example above: 1) cam.eye() returns a copy of original vector _eye 2) 'y' component of this copy is changed to 5 3) write-property came.eye(Vector3) must be called with parameter obtained in previous action. Comments?There are some other options besides making language changes: 1) it seems like you want your class to "do something more" when the entire eye is set but not when just the y component is set. This seems odd to me so I assume it is an artifact of shortening the example for posting. So my first reaction is the current behavior is avoiding a bug in your code.2) returning a pointer from eye() isn't too bad and makes it obvious it is a reference. The line cam.eye.y would then change the copy owned by the Camera. But as I said in 1 this seems like it seems like that opens up a hole to change _eye without doing something more.in this case additian action will not take place.3) add properties to just set or translate one component of eye at a time. For example void eyeY(float new_y) { _eye.y = new_y; //do something more } Then instead of cam.eye.y = 5 you have cam.eyeY = 5.count of such separate methods will became innumerable at some moment4) don't do anything and just leave the eye setter as the only way to change _eye. I don't think users will be confused by the behavior of cam.eye.y = 5I think expression cam.eye.y = 5 is very natural and so such constructions, writen because of blunder, can lead to hiden bugs hard to find.
Dec 20 2004
[snip]change4) don't do anything and just leave the eye setter as the only way to5_eye. I don't think users will be confused by the behavior of cam.eye.y =I think expression cam.eye.y = 5 is very natural and so suchconstructions,writen because of blunder, can lead to hiden bugs hard to find.So what about code like void foo(Vector3 w){w.y = 5;} ... foo(cam.eye) Does it modify the original values in cam? I would be surprised if it did - but then I'm not at all surprised that cam.eye.y changes a copy. Or if you really want to you can try something like struct EyeRef { Vector3* eye; Camera cam; ... void y(float new_y) { eye.y = new_y; cam.doSomething(); } Vector3 toValue(){ return *eye; } } class Camera { ... EyeRef eye() { EyeRef e; e.cam = this; e.eye = &_eye; return e; } } That way cam.eye.y = 5 will set the _eye.y value in cam and call doSomething in cam afterwards - which I think is what you want to have happen. Writing cam.eye.toValue will return a copy of the Vector3. Making the language more complex should be a last resort.
Dec 20 2004
Nail, try changing your example to use the following:public Vector3* eye() { return &_eye; }Pointers aren't preferred in D (they're ugly), but they do exist for reasons aside from legacy compatibility. In this case, simply return a pointer to the struct you wish to access and all will be well. You won't have to change anything else, so don't worry about your code bloating up too badly. Also, if you're exposing a member in this fashion (exposing the whole struct), you might want to do away with an accessor completely. If there are no in/out clauses in your accessors, you're not gaining anything by that extra function call. :) I, like yourself, first expected structs to be pass-by-reference much like classes are; obviously, they are pass-by-value. The more D code I wrote, the more I became to realize that structs are more like heavyweight scalars than lightweight classes. They still have to obey the copy-on-write rule as other scalars do. I think this isn't a flaw in D's design, but rather a deliberate move on Walter's part to provide compatibility with C. To that end, it lets you do *at least* as much as C/C++, and then some. - Pragma at yahoo
Dec 20 2004
I, like yourself, first expected structs to be pass-by-reference much like classes are; obviously, they are pass-by-value. The more D code I wrote, the more I became to realize that structs are more like heavyweight scalars than lightweight classes. They still have to obey the copy-on-write rule as other scalars do. I think this isn't a flaw in D's design, but rather a deliberate move on Walter's part to provide compatibility with C. To that end, it lets you do *at least* as much as C/C++, and then some.Maybe yo're right. The time will show.
Dec 20 2004