|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Why does this.Location.X = 0; generate a compile error?..X (.Y too) are ints with get/set methods so why does trying to set either
one generate a compile error?? This is something that gets many developers confused. As you probably
already know, "Location" is not a variable but a property. This means that the property internal (get) implementation looks something like this: public Point Location { get { return _Point; } } This code is then translated by the compiler to a method like: public Point get_Location() { return _Point; } And there is the problem, what you are getting out of this function is a fresh new Point variable, not a direct reference to the _Point varaible. Keyword here is you are getting a full *new* Point variable so what you are basicaly trying to do is telling the compiler to put a "Point" sturct value into a "Point.X" wich is not a variable and that's why you get the error. What you need to do is to first create a new Point varaible with the new values and then use that to set the new value as: Point myNewPoint == new Point(); myNewPoint.X = 123; myNewPoint.Y = 456; this.Location = myNewPoint; Show quote "Dave" <n***@nowhere.com> wrote in message news:OX0ML8YaGHA.4160@TK2MSFTNGP04.phx.gbl... > .X (.Y too) are ints with get/set methods so why does trying to set either > one generate a compile error?? > Ah, because Point is a struct and not a class and structs are a value type.
I get it. Thanks. Show quote "Rene" <a@b.c> wrote in message news:%235LZgObaGHA.4236@TK2MSFTNGP05.phx.gbl... > This is something that gets many developers confused. As you probably > already know, "Location" is not a variable but a property. This means that > the property internal (get) implementation looks something like this: > > public Point Location > { > get { return _Point; } > } > > This code is then translated by the compiler to a method like: > > public Point get_Location() > { > return _Point; > } > > And there is the problem, what you are getting out of this function is a > fresh new Point variable, not a direct reference to the _Point varaible. > > Keyword here is you are getting a full *new* Point variable so what you > are basicaly trying to do is telling the compiler to put a "Point" sturct > value into a "Point.X" wich is not a variable and that's why you get the > error. > > What you need to do is to first create a new Point varaible with the new > values and then use that to set the new value as: > > Point myNewPoint == new Point(); > myNewPoint.X = 123; > myNewPoint.Y = 456; > this.Location = myNewPoint; > > "Dave" <n***@nowhere.com> wrote in message > news:OX0ML8YaGHA.4160@TK2MSFTNGP04.phx.gbl... >> .X (.Y too) are ints with get/set methods so why does trying to set >> either one generate a compile error?? >> > > Not really, you can actually do what are doing as long as you had a direct
reference to the Point variable: ----------------------------------- public class Test { public Point _Point = new Point(); } Test myTest = new Test(); myTest._Point.X = 0; // This will work ----------------------------------- This is not about value type, this is about the fact that internally you are getting and setting a *Full* Point struct, so assigning just a member of a struct does not work. Show quote "Dave" <n***@nowhere.com> wrote in message news:eRxd%23abaGHA.1020@TK2MSFTNGP02.phx.gbl... > Ah, because Point is a struct and not a class and structs are a value > type. I get it. > > Thanks. > > > "Rene" <a@b.c> wrote in message > news:%235LZgObaGHA.4236@TK2MSFTNGP05.phx.gbl... >> This is something that gets many developers confused. As you probably >> already know, "Location" is not a variable but a property. This means >> that the property internal (get) implementation looks something like >> this: >> >> public Point Location >> { >> get { return _Point; } >> } >> >> This code is then translated by the compiler to a method like: >> >> public Point get_Location() >> { >> return _Point; >> } >> >> And there is the problem, what you are getting out of this function is a >> fresh new Point variable, not a direct reference to the _Point varaible. >> >> Keyword here is you are getting a full *new* Point variable so what you >> are basicaly trying to do is telling the compiler to put a "Point" sturct >> value into a "Point.X" wich is not a variable and that's why you get the >> error. >> >> What you need to do is to first create a new Point varaible with the new >> values and then use that to set the new value as: >> >> Point myNewPoint == new Point(); >> myNewPoint.X = 123; >> myNewPoint.Y = 456; >> this.Location = myNewPoint; >> >> "Dave" <n***@nowhere.com> wrote in message >> news:OX0ML8YaGHA.4160@TK2MSFTNGP04.phx.gbl... >>> .X (.Y too) are ints with get/set methods so why does trying to set >>> either one generate a compile error?? >>> >> >> > > Rene wrote:
> Dave wrote: .... or if Point was a reference type, in which case the property getter >> Ah, because Point is a struct and not a class and structs are a value >> type. I get it. > > Not really, you can actually do what are doing as long as you had a > direct reference to the Point variable: doesn't return a copy of the variable, but rather a new reference to it. -cd Carl Daniel [VC++ MVP]
<cpdaniel_remove_this_and_nospam@mvps.org.nospam> wrote: > Rene wrote: No, it would return a copy of the variable's value. The variable isn't > > Dave wrote: > >> Ah, because Point is a struct and not a class and structs are a value > >> type. I get it. > > > > Not really, you can actually do what are doing as long as you had a > > direct reference to the Point variable: > > ... or if Point was a reference type, in which case the property getter > doesn't return a copy of the variable, but rather a new reference to it. the same as its value - what would be returned would have nothing to do with the variable itself, it would just have the same value. Specifically, there is nothing you could do with the returned value which would change the value of the original variable. You could change the contents of the object that value referred to, but that's not changing the variable's value. -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too
Show quote
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message I think that we all know what he means.news:MPG.1ebbc546cda7de1c98d173@msnews.microsoft.com... > Carl Daniel [VC++ MVP] > <cpdaniel_remove_this_and_nospam@mvps.org.nospam> wrote: >> Rene wrote: >> > Dave wrote: >> >> Ah, because Point is a struct and not a class and structs are a value >> >> type. I get it. >> > >> > Not really, you can actually do what are doing as long as you had a >> > direct reference to the Point variable: >> >> ... or if Point was a reference type, in which case the property getter >> doesn't return a copy of the variable, but rather a new reference to it. > > No, it would return a copy of the variable's value. The variable isn't > the same as its value - what would be returned would have nothing to do > with the variable itself, it would just have the same value. > Specifically, there is nothing you could do with the returned value > which would change the value of the original variable. You could change > the contents of the object that value referred to, but that's not > changing the variable's value. The lesson to be learned from this is that value types with setable properties are a bad idea i.e. changing value types should be an all or nothing affair. Note there are at least as many problems caused by using reference types. The usual scenario is that you have a class with something like a LocationChangedEvent which is only raised on "obj.Location = newLocation;" and not "obj.Location.X = 42;" The real solution is C++ const but it isn't going to happen :( Nick Hounsome <N***@NickHounsome.Me.Uk> wrote:
> > No, it would return a copy of the variable's value. The variable isn't I suspect the post I was replying to does, but I've learned to my cost > > the same as its value - what would be returned would have nothing to do > > with the variable itself, it would just have the same value. > > Specifically, there is nothing you could do with the returned value > > which would change the value of the original variable. You could change > > the contents of the object that value referred to, but that's not > > changing the variable's value. > > I think that we all know what he means. that careless misuse of terminology can confuse those reading the replies. > The lesson to be learned from this is that value types with setable Agreed.> properties are a bad idea i.e. changing value types should be an all or > nothing affair. > Note there are at least as many problems caused by using reference types. Hmm... I'd say at that point that it's carelessness on the part of the > The usual scenario is that you have a class with something like a > LocationChangedEvent which is only raised on "obj.Location = newLocation;" > and not "obj.Location.X = 42;" class designer - either the Location (or whatever) class, or the parent class. If the Location class is designed to cope with situations like this, the parent could subscribe to *its* change event. I've rarely found this kind of thing particularly necessary though. I find that reference semantics are generally a lot easier to understand - there are fewer "gotchas", partly due to the lack of boxing/unboxing. > The real solution is C++ const but it isn't going to happen :( Indeed.-- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too Rene <a@b.c> wrote:
Show quote > Not really, you can actually do what are doing as long as you had a direct No, it *is* about value types. It's specifically described in the C# > reference to the Point variable: > ----------------------------------- > public class Test > { > public Point _Point = new Point(); > } > > Test myTest = new Test(); > myTest._Point.X = 0; // This will work > ----------------------------------- > > This is not about value type, this is about the fact that internally you are > getting and setting a *Full* Point struct, so assigning just a member of a > struct does not work. spec, section 14.13.1 (ECMA numbering, 1.1 edition) <quote> When a property or indexer declared in a struct-type is the target of an assignment, the instance expression associated with the property or indexer access must be classified as a variable. </quote> So it's because it's a property *and* because it's accessing a value type. If this rule did not exist, you could do this.Location.X=0, but it would be equivalent to: Point p = this.Location; p.X=0; which would be a no-op. The compiler is guarding you against that, and it's only an issue because Point is a value type. -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too Seeshhh John, you are such a nerd! Just when I was all happy about helping
out BAMM WHAMM here comes John with his closing remarks! :) The point that I wanted to get across was that properties look like fields but they are really methods. I also wanted to point out the what the original poster was doing it's possible to do as long as the "Location" was a field. Cheers Show quote "Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message news:MPG.1ebbc4e523b4e2f98d172@msnews.microsoft.com... > Rene <a@b.c> wrote: >> Not really, you can actually do what are doing as long as you had a >> direct >> reference to the Point variable: >> ----------------------------------- >> public class Test >> { >> public Point _Point = new Point(); >> } >> >> Test myTest = new Test(); >> myTest._Point.X = 0; // This will work >> ----------------------------------- >> >> This is not about value type, this is about the fact that internally you >> are >> getting and setting a *Full* Point struct, so assigning just a member of >> a >> struct does not work. > > No, it *is* about value types. It's specifically described in the C# > spec, section 14.13.1 (ECMA numbering, 1.1 edition) > > <quote> > When a property or indexer declared in a struct-type is the target of > an assignment, the instance expression associated with the property or > indexer access must be classified as a variable. > </quote> > > So it's because it's a property *and* because it's accessing a value > type. If this rule did not exist, you could do this.Location.X=0, but > it would be equivalent to: > > Point p = this.Location; > p.X=0; > > which would be a no-op. The compiler is guarding you against that, and > it's only an issue because Point is a value type. > > -- > Jon Skeet - <sk***@pobox.com> > http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet > If replying to the group, please do not mail me too > If this rule did not exist, you could do this.Location.X=0, but I am not sure if I agree with that because if I follow the same logic, if I > it would be equivalent to: > > Point p = this.Location; > p.X=0; try to set the "this.Top = 0" it would be equivalent to: int i = this.Top; i = 0; This would also be a no-op (I assume this is stands for no-operation) so the compiler should not allow me to do that either but it does. Going back to the Location property again, In my opinion, the compiler will internally try to use the set_Location(Point newPoint) function to set the new value for the Location property. As we all already know, this function is automatically created by the compiler. The only thing that makes sense to pass as the argument to this function is a full Point variable and not just a member like "someNewPoint.X". You just can't partially change a Point value like that; it would be like trying to change an integer value of zero to a one by trying to pass only the one bit that it needs to change form a 0 to a 1. You don't do that, what you do is to pass the whole integer value as in "00000000 00000000 00000000 00000001". I believe this is really why the compiler won't allow the code to compile. Rene <a@b.c> wrote:
> > If this rule did not exist, you could do this.Location.X=0, but No, it wouldn't - because this.Top is a property on its own, and that's > > it would be equivalent to: > > > > Point p = this.Location; > > p.X=0; > > I am not sure if I agree with that because if I follow the same logic, if I > try to set the "this.Top = 0" it would be equivalent to: > > int i = this.Top; > i = 0; okay because "this" is a variable. You can set a property on an value type expression that is classified as a variable, but not on a value type expression that is classified as a value (as per the spec I quoted before). > This would also be a no-op (I assume this is stands for no-operation) so the No, it won't use the Location setter, because you can't do it in the > compiler should not allow me to do that either but it does. > > Going back to the Location property again, In my opinion, the compiler will > internally try to use the set_Location(Point newPoint) function to set the > new value for the Location property. As we all already know, this function > is automatically created by the compiler. first place. It *shouldn't* use the Location setter either, because you haven't said to. If the Location setter had some other side effect, it would be highly counter-intuitive to have that side effect come when nothing had done this.Location = <something>; > The only thing that makes sense to pass as the argument to this function is Yes, you can only give a full value to the Location setter. But the > a full Point variable and not just a member like "someNewPoint.X". Location setter isn't being called here. The only setter being called is the one on Point. The Location property *getter* is called. > You just can't partially change a Point value like that; it would be like No, you *can* change half a Point value exactly like that, because > trying to change an integer value of zero to a one by trying to pass only > the one bit that it needs to change form a 0 to a 1. You don't do that, > what you do is to pass the whole integer value as in "00000000 00000000 > 00000000 00000001". (unfortunately IMO) Point is a mutable value type. However, changing the value of any part of one Point variable won't change the value of any other Point variable. > I believe this is really why the compiler won't allow the code to compile. Not really - it's because invoking the accessor (the "get" method) returns a value to the caller. Modifying that value (whether half of it or not) won't do anything. The point is that it's *only* using the getter, *not* the setter. I suggest you have a look at the thread called "csharp language idea" started on April 27th in the C# group for more about this. -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too |
|||||||||||||||||||||||