Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Consider the Foo struct as follows:

struct Foo
{
  public float X;
  public float Y;

  public Foo(float x, float y)
  {
    this.X = x;
    this.Y = y;
  }

  public void Change(float x)
  {
    this.X = x;
  }
}

I understand modifying the field in the constructor, that's perfectly logical to me and my understanding of structs as value, number-like immutable types.

However, since one can't do:

Foo bar = new Foo(1, 2);
bar.X = 5;

Why can one use:

Foo bar = new Foo(1, 2);
bar.Change(5);

EDIT: If structs are mutable, then why can't they be modified when in a list or returned from a property?

Cannot modify expression because it is not a variable

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
236 views
Welcome To Ask or Share your Answers For Others

1 Answer

Since one cannot do

Foo bar = new Foo(1, 2); 
bar.X = 5; 

Why can one use:

Foo bar = new Foo(1, 2); 
bar.Change(5); 

Your original question actually cannot be answered because it is predicated on a completely false assumption. Both code samples are perfectly legal, and so the question about why one is illegal is nonsensical. Let's move on to your follow-up question:

If structs are mutable, then why can't they be modified when in a list or returned from a property?

Because variables are mutable and values are immutable.

That's why they're called "variables", after all, because they can change.

When you say "bar.X = 5", "bar" is a local variable. Variables are allowed to change.

When you say "bar.Change(5)", "bar" is a local variable. Variables are allowed to change.

When you say "myArray[123].X = 5", "myArray[123]" is an array element and an array element is a variable. Variables are allowed to change.

When you say "myDictionary[123].X = 5", "myDictionary[123]" is not a variable. The value is returned from the dictionary, not a reference to the storage location. Since that is a value, not a variable, there is nothing there that can change, so the compiler does not allow it to change.

A subtle point is that when you attempt to change a field, the receiver must be a variable. If it is not a variable, it makes no sense; you are clearly attempting to mutate a variable and there's nothing there to mutate. When you call a method, the receiver must be a variable but what if you have a value? The method might not attempt to mutate anything, and so should be allowed to succeed. What the compiler actually does if the receiver of a method call on a struct is not a variable, then it makes a new temporary local variable and calls the method with that variable. So if you say: "myDictionary[123].Change(5);" that is the same as saying

var temp = myDictionary[123];
temp.Change(5);

Here "temp" is a variable, and the mutating method is allowed to change the temporary copy.

Is that now clear? The key takeaway here is variables can change.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...