In C# , Are Value types mutable or immutable ?
Asked Answered
E

4

19

Value types behavior shows that whatever value we are holding cannot be changed through some other variable .

But I still have a confusion in my mind about what i mentioned in the title of this post . Can anyone clarify?

E answered 17/8, 2011 at 4:50 Comment(0)
V
28

Value types can be either mutable or (modulo some weird edge cases) immutable, depending on how you write them.

Mutable:

public struct MutableValueType
{
    public int MyInt { get; set; }
}

Immutable:

public struct ImmutableValueType
{
    private readonly int myInt;
    public ImmutableValueType(int i) { this.myInt = i; }

    public int MyInt { get { return this.myInt; } }
}

The built-in value types (int, double and the like) are immutable, but you can very easily create your own mutable structs.

One piece of advice: don't. Mutable value types are a bad idea, and should be avoided. For example, what does this code do:

SomeType t = new SomeType();
t.X = 5;

SomeType u = t;
t.X = 10;

Console.WriteLine(u.X);

It depends. If SomeType is a value type, it prints 5, which is a pretty confusing result.

See this question for more info on why you should avoid mutable value types.

V2 answered 17/8, 2011 at 4:53 Comment(11)
Just two observations - in the mutable case, the field could (and probably should) still be behind a property. In the immutable case, the field could be explicitly readonly.Ketti
@Marc Good points. I actually considered going back and making the readonly edit; suppose I'll make both now. Thanks.V2
@dlev, so when you have something like the following. int i = 5; i = 5+2; The 5+2 is passed to a new int and the referenced returned to i? IMHO when SomeType prints 5 I'm not confused, it's when SomeType prints 10 that boggles me. Good answer btw.Croak
@Croak You're conflating variables with their contents a bit. i is a variable, which contains the integer 5. When you say i = 5 + 2, you put a new integer (7) into the memory held by i. What you don't do is change the integer 5 into the integer 7. And thanks for the compliment :)V2
@dlev, but by changing the memory held by <code>i</code> are we not changing the value of <code>i</code> making it mutable. I've always known <code>Strings</code> as being immutable, hence when you do someting like this <code>str = str + "change";</code> you are in fact calling the <code>String.Concat</code> which creates a new block of memory and then points str to that block of memory. Is this what is happening with <code>i</code> or does the Integers original memory block get changed? Hope that makes sense.Croak
@Croak i itself is definitely mutable; it's a variable, and it can vary. The Int32 struct that it stored, though, is not mutated. It is replaced wholesale by a new one. The problem with value types is that they don't "own" their storage. i's memory and the memory used for 5 are the same. So while assigning a new int to i does replace that memory, it's still not considered to be mutating the struct.V2
@dlev, thanks for the mini lesson, really cleared up some of my understandings. Thanks again.Croak
In your example, if SomeType is a value type with an integer field X, u.X will be 5. That information and the code above are sufficient to show that information; it should hardly be "unexpected". Now suppose t were a class type, and anyplace between the creation of t and the WriteLine call--even before the "t.x=10", there was a call to SomeInheritableClassObject.SomeVirtualFunction(t). Without examining all possible overrides of SomeVirtualFunction, there's no way to know what the WriteLine would output. I'd regard the predictable behavior of mutable structs to be far preferable.Zacharia
@MarcGravell: Why should a mutable struct field be hidden behind a property? If a struct has a public field X, a C compiler won't have to guess at whether SomeReadOnlyStructure.X += 4; should be legal, or whether someReadOnlyVariable = SomeReadOnlyStructure.X needs to make a copy of the structure because the X getter might modify it. Properties on structures are fine when they make sense, but if the implementation of the property can't change without breaking things, what is gained by using a property rather than a field?Zacharia
I have my doubt about your example of "inmutable", seems that is not inmutable, as MSDN says: when a property getter returns a value type, the caller receives a copy. Because the copy is created implicitly, developers might not be aware that they are mutating the copy, and not the original value. Also, some languages (dynamic languages, in particular) have problems using mutable value types because even local variables, when dereferenced, cause a copy to be made. msdn.microsoft.com/en-us/library/ms229031%28v=vs.110%29.aspxShrift
I don't think this is a convincing example - why would ever right code like this? I mean: you present this as an example why mutable value types are bad, but the reference-typed variable case is at least as bad - when you read u.X and try to figure out what that might be, you might see that u is initialized with X=5 and never modified, and might easily draw the wrong conclusion that u.X is 5 too. By mixing aliasing and mutation, you now need to play the (impossible) game of following all those aliases... and good luck if SomeType plays similar tricks internally...Grazia
D
3

all primitive value types like int, double,float are immutable.But structs by itself are mutable.so you have to take measures to make them as immutable as it can create lot of confusions.

Downgrade answered 17/8, 2011 at 4:52 Comment(2)
Ok , But wat about reference types ? while reading through documents i came to know that they can be either mutable or immutable . how is that ?E
@Nitesh . That also depends upon how you implement it .The System.Text.StringBuilder class is an example of a mutable reference type. It contains members that can change the value of an instance of the class. An example of an immutable reference type is the System.String class. After it has been instantiated, its value can never changeDowngrade
Z
1

Any value-type instance which holds any information can be mutated by code which can write the storage location wherein it are contained, and no value type-instance can be mutated by code which cannot write the storage location wherein it is contained. These characteristics make privately-held storage locations of mutable value types ideal data containers in many scenarios, since they combine the updating convenience that stems from mutability, with the control that would come from immutability. Note that it is possible to write the code for a value type in such a way that it's impossible to mutate an existing instance without first having an instance (perhaps a newly created temporary instance) which contains the desired data, and overwriting the contents of the former instance with the contents of the latter, but that won't make the value type any more or less mutable than it would have been absent such ability. In many cases, it merely serves to make mutation awkward and to make it look as though a statement like:

  MyKeyValuePair =
    new KeyValuePair<long,long>(MyKeyValuePair.Key+1, MyKeyValuePair.Value+1>;

will create a new instance but leave the existing instance unaffected. If KeyValuePair were an immutable class, and one thread was performing a MyKeyValuePair.ToString() while another thread was executing the above code, the ToString call would act upon either the old or new instance, and would thus yield either both old values or both new values. Because KeyValuePair is a struct, however, the above statement will create a new instance, but it won't make MyKeyValuePair refer to the new instance--it will merely use the new instance as a template whose fields will be copied to MyKeyValuePair. If KeyValuePair were a mutable struct, the most natural expression of the likely-intended meaning for the above code would be more like:

  MyKeyValuePair.Key += 1;
  MyKeyValuePair.Value += 1;

or perhaps:

  var temp = MyKeyValuePair;
  MyKeyValuePair.Key = temp.Key+1;
  MyKeyValuePair.Value = temp.Value+1;

and the threading implications would be much clearer.

Zacharia answered 15/3, 2012 at 16:57 Comment(0)
N
0

I wonder if some of the responders here were missing a point that might be worth mentioning.

I could be under a misimpression, so please correct me if I'm wrong; but my understanding is that one key difference between a value type and a reference type is that a value type can be used to establish a referenceable block of homogenous, contiguous memory. (Remember that structs existed long before "fixed" and "span" and all the effort to facilitate convenient and robust use of "unsafe" code sections.)

An array of classes, even small ones with value type members, is an array of pointers. Iterating over it and referencing each class's members is likely to require the CPU to go all the way out to main memory for each class.

An array of structs, on the other hand, is materialized within the array. It's one big block of contiguous memory. Iterating over that can make a whole lot better use of the CPU caches. A whole lot.

If that's your reason for using a container of structs (and I think that might be my main reason for ever using a struct at all), then you're likely to want to be able to reference and update individual struct members within that block of memory without requiring the CPU to create one or more copies of an entire struct at a time.

In this whole category of circumstances, which it seems to me is really what motivates the existence of the C# struct in the first place, making struct members read-only or immutable may very well completely defeat the purpose.

I imagine some may dump on me, here, saying that if I'm so worried about performance, I shouldn't be using C#; but as Mike Acton famously said, "People not worrying about performance is why my Word takes 30 seconds to come up."

Nucleoprotein answered 14/11, 2023 at 10:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.