   [C#] struct and auto properties
  Hey,I caught the bat habit to over use auto properties and got bitten by that.struct Foo {    void Operation() { i++; }    private int i;}class Bar {    void Operation()    {   foo.Operation();   // foo.i == 0, because foo is a struct and the accessor returns a copy!    }    public Foo foo { get; private set; }}My question (or rant if you prefer :P) is why won't the compiler generate a warning in this situation? It seems obvious that the Operation will affect an unreferenced copy of the real Foo instance.Any thoughts?   
Quote:I caught the bat habit to over use auto properties and got bitten by that.The scenario you describe has nothing to do with automatic properties (nor are they a bad habit). It has everything to do with forgetting to think about the value semantics of the type used in the property (it would happen with manual properties as well).Quote:My question (or rant if you prefer :P) is why won't the compiler generate a warning in this situation? It seems obvious that the Operation will affect an unreferenced copy of the real Foo instance.It's not obvious to the compiler, only to you. Generating a warning in this scenario would create a false positive more often than not; it would be entirely fine for the operation to have side effects, for example.   ;  An automatic (or manual, really) property involving value types is perfectly legitimate, so the warning couldn't be where you define the property. The only other place the warning would go is where you call Operation(), and a warning only makes sense if Operation() doesn't have any other side-effects. So the compiler would have to know the internals of the method when it compiles your reference to it: which it can't do (the method could be an external reference, for example).Edit: too slow!   ;Quote:Original post by jpetrieThe scenario you describe has nothing to do with automatic properties (nor are they a bad habit). It has everything to do with forgetting to think about the value semantics of the type used in the property (it would happen with manual properties as well).It is a bad habit to use them as a standard and convenient replacement for a public field:public Foo foo { get; private set; } // instead of public Foo fooThe above works fine with simple type or reference types, but when it comes to structs, it can break. I know I'm the one to blame here, obviously.However, the compiler will generate an error for code like this:struct Foo {    void Operation() { i++; }    public int i;}class Bar {    void Operation()    {   foo.Operation(); // no complaint   foo.i++; // Complains that foo is not a variable, yet I was able to call Operation() on it.    }    public Foo foo { get; private set; }};  This is one of the reasons why it is often recommended that .NET value types should be immutable, although it is also much argued :). There's a discussion on this here.   ;Quote:Original post by janta   foo.Operation(); // no complaint   foo.i++; // Complains that foo is not a variable, yet I was able to call As I said, it gives an error in the second case because it know all the details about what "i++" does. It can't complain about calling a method, though, because it doesn't know what the method does at the point where you're calling it. It's only because you can see that the method does nothing useful that you want there to be an error - the compiler can't see that (the method might be defined in an external reference, for example).As an example, say you define your struct Foo as follows:struct Foo{  void Operation() { Console.WriteLine("{0}", i); }  public int i;}In this case, calling Operation() from a property is perfectly legitimate (it doesn't matter that you get a copy). The compiler doesn't know that at the time you call it, however.   ;  Yes, I understand what you're saying Codeka. I'm not trying to make a point here, I know I'm wrong and I understand why. I just though it could still be an interesting discussion ;)Often, a member function will have side effects on the object it is called. Therefore I thought maybe a level-4 warning (which would give many false positive, I understand that too) could have been relevant.   ;Quote:It is a bad habit to use them as a standard and convenient replacement for a public field:It is absolutely not. Whether or not its a correct design decision is one thing -- but the converse is also true (many APIs based on reflection will not consider fields, looking only to properties, for example). But its not a bad habit in the scenario you've shown (which is to say in the absence of more specific information). It's just an orthogonal one.One could even make the argument that the bad habit is in preferring the public fields at all. Prior to the introduction of automatic properties public fields had a reasonable rationale for existing (less code to maintain), but they still suffered the reflection-related issues as many APIs did and still do consider only properties, since you can do more with them. Automatic properties address that one minor issue and make it even less favorable to have public fields.   ;  Well, I understand your point, but I mean it is a "bad habit" (at least for me) because I had not realized until today that an automatic property like "{get; private set;}" is not strictly equivalent to "a public field with read only permission"In my situation, I think a correct implementation implies the following:struct Foo {    void Operation() { i++; }    private int i;}class Bar {    void Operation()    {   foo.Operation();   // foo.i was incremented    }    private Foo foo;    public Foo Foo { get { return foo; } }}What am I missing? Would you do it differently?If I stick with the auto properties, I would have think that my code would have been equivalent to this:struct Foo {    void Operation() { i++; }    public int i;}class Bar {    void Operation()    {   foo.Operation(); // no complaint   // Equivalent to:   Foo copy = foo;   copy.Operation();   foo = copy; // Obviously this one does not happen, which is where I got    Blah++;   // Equivalent to:   int copy = Blah;   copy++;   Blah= copy;    }    public Foo foo { get; private set; }    public int Blah { get; private set; }};Quote:Original post by jantaOften, a member function will have side effects on the object it is called. Therefore I thought maybe a level-4 warning (which would give many false positive, I understand that too) could have been relevant.I dunno, I think a warning with many false positive is worse than no warning at all.   