[ACCEPTED]-Are value types immutable by definition?-value-type

Accepted answer
Score: 55

An object is immutable if its state doesn’t 83 change once the object has been created.

Short 82 answer: No, value types are not immutable 81 by definition. Both structs and classes can be either mutable or immutable. All four combinations are 80 possible. If a struct or class has non-readonly 79 public fields, public properties with setters, or 78 methods which set private fields, it is 77 mutable because you can change its state 76 without creating a new instance of that 75 type.


Long answer: First of all, the question 74 of immutability only applies to structs 73 or classes with fields or properties. The 72 most basic types (numbers, strings, and 71 null) are inherently immutable because there 70 is nothing (field/property) to change about 69 them. A 5 is a 5 is a 5. Any operation on 68 the 5 only returns another immutable value.

You 67 can create mutable structs such as System.Drawing.Point. Both 66 X and Y have setters which modify the struct's 65 fields:

Point p = new Point(0, 0);
p.X = 5;
// we modify the struct through property setter X
// still the same Point instance, but its state has changed
// it's property X is now 5

Some people seem to confuse immutablity 64 with the fact that value types are passed 63 by value (hence their name) and not by reference.

void Main()
{
    Point p1 = new Point(0, 0);
    SetX(p1, 5);
    Console.WriteLine(p1.ToString());
}

void SetX(Point p2, int value)
{
    p2.X = value;
}

In 62 this case Console.WriteLine() writes "{X=0,Y=0}". Here p1 was 61 not modified because SetX() modified p2 which is 60 a copy of p1. This happens because p1 is a value type, not 59 because it is immutable (it isn't).

Why should value types 58 be immutable? Lots of reasons... See this question. Mostly 57 it's because mutable value types lead to 56 all sorts of not-so-obvious bugs. In the 55 above example the programmer might have 54 expected p1 to be (5, 0) after calling SetX(). Or imagine 53 sorting by a value which can later change. Then 52 your sorted collection will no longer be 51 sorted as expected. The same goes for dictionaries 50 and hashes. The Fabulous Eric Lippert (blog) has written a whole series about immutability and why 49 he believes it's the future of C#. Here's one of his examples that 48 lets you "modify" a read-only 47 variable.


UPDATE: your example with:

this.readOnlyPoint.Offset(3, 4); // Is still (1, 2).

is exactly 46 the what Lippert referred to in his post 45 about modifying read-only variables. Offset(3,4) actually 44 modified a Point, but it was a copy of readOnlyPoint, and it was 43 never assigned to anything, so it's lost.

And 42 that is why mutable value types are evil: They 41 let you think you are modifying something, when 40 sometimes you are actually modifying a copy, which 39 leads to unexpected bugs. If Point was immutable, Offset() would 38 have to return a new Point, and you would not 37 have been able to assign it to readOnlyPoint. And then 36 you go "Oh right, it's read-only for a reason. Why was I trying to change it? Good thing the compiler stopped me now."


UPDATE: About your rephrased request... I 35 think I know what you're getting at. In 34 a way, you can "think" of structs 33 as being internally immutable, that modifying a struct 32 is that same as replacing it with a modified 31 copy. It might even be what the CLR does 30 internally in memory, for all I know. (That's 29 how flash memory works. You cannot edit 28 just a few bytes, you need to read a whole 27 block of kilobytes into memory, modify the 26 few you want, and write the whole block 25 back.) However, even if they were "internally 24 immutable", that is an implementation 23 detail and for us developers as users of 22 structs (their interface or API, if you 21 will), they can be changed. We can't ignore 20 that fact and "think of them as immutable".

In 19 a comment you said "you cannot have 18 a reference to the value of field or variable". You 17 are assuming that every struct variable 16 has a different copy, such that modifying 15 one copy does not affect the others. That 14 is not entirely true. The lines marked below 13 are not replaceable if...

interface IFoo { DoStuff(); }
struct Foo : IFoo { /* ... */ }

IFoo otherFoo = new Foo();
IFoo foo = otherFoo;
foo.DoStuff(whatEverArgumentsYouLike); // line #1
foo = foo.DoStuff(whatEverArgumentsYouLike); // line #2

Lines #1 and #2 12 do not have the same results... Why? Because 11 foo and otherFoo refer to the same boxed instance of Foo. Whatever is 10 changed in foo in line #1 reflects in otherFoo. Line 9 #2 replaces foo with a new value and does nothing 8 to otherFoo (assuming that DoStuff() returns a new IFoo instance 7 and does not modify foo itself).

Foo foo1 = new Foo(); // creates first instance
Foo foo2 = foo1; // create a copy (2nd instance)
IFoo foo3 = foo2; // no copy here! foo2 and foo3 refer to same instance

Modifying foo1 won't 6 affect foo2 or foo3. Modifying foo2 will reflect in 5 foo3, but not in foo1. Modifying foo3 will reflect in 4 foo2 but not in foo1.

Confusing? Stick to immutable 3 value types and you eliminate the urge of 2 modifying any of them.


UPDATE: fixed typo 1 in first code sample

Score: 11

Mutability and value types are two separate 5 things.

Defining a type as a value type, indicates 4 that the runtime will copy the values instead 3 of a reference to the runtime. Mutability, on 2 the other hand, depends on the implementation, and 1 each class can implement it as it wants.

Score: 8

You can write structs that are mutable, but 9 it is best practice to make value types 8 immutable.

For instance DateTime always 7 creates new instances when doing any operation. Point 6 is mutable and can be changed.

To answer 5 your question: No, they are not immutable 4 by definition, it depends on the case if 3 they should be mutable or not. For instance, if 2 they should serve as dictionary keys, they 1 should be immutable.

Score: 5

If you take your logic far enough, then 49 all types are immutable. When you modify a 48 reference type, you could argue that you're 47 really writing a new object to the same 46 address, rather than modifying anything.

Or 45 you could argue that everything is mutable, in 44 any language, because occasionally memory 43 that had previously been used for one thing, will 42 be overwritten by another.

With enough abstractions, and 41 ignoring enough language features, you can 40 get to any conclusion you like.

And that 39 misses the point. According to .NET spec, value 38 types are mutable. You can modify it.

int i = 0;
Console.WriteLine(i); // will print 0, so here, i is 0
++i;
Console.WriteLine(i); // will print 1, so here, i is 1

but 37 it is still the same i. The variable i is 36 only declared once. Anything that happens 35 to it after this declaration is a modification.

In 34 something like a functional language with 33 immutable variables, this would not be legal. The 32 ++i would not be possible. Once a variable 31 has been declared, it has a fixed value.

In 30 .NET, that is not the case, there is nothing 29 to stop me from modifying the i after it's 28 been declared.

After thinking about it a 27 bit more, here's another example that might 26 be better:

struct S {
  public S(int i) { this.i = i == 43 ? 0 : i; }
  private int i;
  public void set(int i) { 
    Console.WriteLine("Hello World");
    this.i = i;
  }
}

void Foo {
  var s = new S(42); // Create an instance of S, internally storing the value 42
  s.set(43); // What happens here?
}

On the last line, according to 25 your logic, we could say that we actually 24 construct a new object, and overwrite the 23 old one with that value. But that's not 22 possible! To construct a new object, the 21 compiler has to set the i variable to 42. But 20 it's private! It is only accessible through 19 a user-defined constructor, which explicitly 18 disallows the value 43 (setting it to 0 17 instead), and then through our set method, which 16 has a nasty side-effect. The compiler has 15 no way of just creating a new object with the 14 values it likes. The only way in which s.i can 13 be set to 43 is by modifying the current object 12 by calling set(). The compiler can't just do 11 that, because it would change the behavior 10 of the program (it would print to the console)

So 9 for all structs to be immutable, the compiler 8 would have to cheat and break the rules 7 of the language. And of course, if we're 6 willing to break the rules, we can prove 5 anything. I could prove that all integers 4 are equal too, or that defining a new class 3 will cause your computer to catch fire. As 2 long as we stay within the rules of the 1 language, structs are mutable.

Score: 4

I don't want to complicate reasoning about 13 this by considering ref parameters and boxing. I 12 am also aware that p = p.Offset(3, 4); expresses immutability 11 much better than p.Offset(3, 4); does. But the question 10 remains - aren't value types immutable 9 by definition?

Well, then you're not really 8 operating in the real world, are you? In 7 practice, the propensity of value types 6 to make copies of themselves as they move 5 between functions meshes well with immutability, but 4 they aren't actually immutable unless you 3 make them immutable, since, as you pointed 2 out, you can use references to them just 1 like anything else.

Score: 4

aren't value types immutable by definition?

No 5 they're not: if you look at the System.Drawing.Point struct 4 for example, it has a setter as well as 3 a getter on its X property.

However it may 2 be true to say that all value types should be 1 defined with immutable APIs.

Score: 2

I think the confusion is that if you have 19 a reference type that should act like a 18 value type it's a good idea to make it immutable. One 17 of the key differences between value types 16 and reference types is that a change made 15 through one name on a ref type can show 14 up in the other name. This doesn't happen 13 with value types:

public class foo
{
    public int x;
}

public struct bar
{
    public int x;
}


public class MyClass
{
    public static void Main()
    {
        foo a = new foo();
        bar b = new bar();

        a.x = 1;
        b.x = 1;

        foo a2 = a;
        bar b2 = b;

        a.x = 2;
        b.x = 2;

        Console.WriteLine( "a2.x == {0}", a2.x);
        Console.WriteLine( "b2.x == {0}", b2.x);
    }
}

Produces:

a2.x == 2
b2.x == 1

Now, if you have 12 a type that you'd like to have value semantics, but 11 don't want to actually make it a value type 10 - maybe because the storage it requires 9 is too much or whatever, you should consider 8 that immutability is part of the design. With 7 an immutable ref type, any change made to 6 an existing reference produces a new object 5 instead of change the existing one, so you 4 get the value type's behavior that whatever 3 value you're holding cannot be changed through 2 some other name.

Of course the System.String 1 class is a prime example of such behavior.

Score: 2

Last year I wrote a blog post regarding 28 the problems you can run into by not making 27 structs immutable.

The full post can be read here

This is an example of 26 how things can go horribly wrong:

//Struct declaration:

struct MyStruct
{
  public int Value = 0;

  public void Update(int i) { Value = i; }
}

Code sample:

MyStruct[] list = new MyStruct[5];

for (int i=0;i<5;i++)
  Console.Write(list[i].Value + " ");
Console.WriteLine();

for (int i=0;i<5;i++)
  list[i].Update(i+1);

for (int i=0;i<5;i++)
  Console.Write(list[i].Value + " ");
Console.WriteLine();

The 25 output of this code is:

0 0 0 0 0
1 2 3 4 5

Now let's do the 24 same, but substitute the array for a generic 23 List<>:

List<MyStruct> list = new List<MyStruct>(new MyStruct[5]); 

for (int i=0;i<5;i++)
  Console.Write(list[i].Value + " ");
Console.WriteLine();

for (int i=0;i<5;i++)
  list[i].Update(i+1);

for (int i=0;i<5;i++)
  Console.Write(list[i].Value + " ");
Console.WriteLine();

The output is:

0 0 0 0 0
0 0 0 0 0

The explanation is very simple. No, it's 22 not boxing/unboxing...

When accessing elements 21 from an array, the runtime will get the 20 array elements directly, so the Update() method 19 works on the array item itself. This means 18 that the structs itself in the array are 17 updated.

In the second example, we used a 16 generic List<>. What happens when we access a 15 specific element? Well, the indexer property 14 is called, which is a method. Value types 13 are always copied when returned by a method, so 12 this is exactly what happens: the list's 11 indexer method retrieves the struct from 10 an internal array and returns it to the 9 caller. Because it concerns a value type, a 8 copy will be made, and the Update() method 7 will be called on the copy, which of course 6 has no effect on the list's original items.

In 5 other words, always make sure your structs 4 are immutable, because you are never sure 3 when a copy will be made. Most of the time 2 it is obvious, but in some cases it can 1 really surprise you...

Score: 1

No, they are not. Example:

Point p = new Point (3,4);
Point p2 = p;
p.moveTo (5,7);

In this example 34 moveTo() is an in-place operation. It changes the structure 33 which hides behind the reference p. You can 32 see that by look at p2: It's position will 31 also have changed. With immutable structures, moveTo() would 30 have to return a new structure:

p = p.moveTo (5,7);

Now, Point is 29 immutable and when you create a reference 28 to it anywhere in your code, you won't get 27 any surprises. Let's look at i:

int i = 5;
int j = i;
i = 1;

This is different. i is 26 not immutable, 5 is. And the second assignment 25 doesn't copy a reference to the structure 24 which contains i but it copies the content 23 of i. So behind the scenes, something completely 22 different happens: You get a complete copy 21 of the variable instead of only a copy of 20 the address in memory (the reference).

An 19 equivalent with objects would be the copy 18 constructor:

Point p = new Point (3,4);
Point p2 = new Point (p);

Here, the internal structure 17 of p is copied into a new object/structure 16 and p2 will contain the reference to it. But 15 this is a pretty expensive operation (unlike 14 the integer assignment above) which is why 13 most programming languages make the distinction.

As 12 computers become more powerful and get more 11 memory, this distinction is going to go 10 away because it causes an enormous amount 9 of bugs and problems. In the next generation, there 8 will only be immutable objects, any operation 7 will be protected by a transaction and even 6 an int will be a full blown object. Just like 5 garbage collection, it will be a big step 4 forward in program stability, cause a lot 3 of grief in the first few years but it will 2 allow to write dependable software. Today, computers 1 just aren't fast enough for this.

Score: 1

No, value types are not immutable by definition.

First, I 4 should better have asked the question "Do 3 value types behave like immutable types?" instead 2 of asking if they are immutable - I assume 1 this caused a lot of confusion.

struct MutableStruct
{
    private int state;

    public MutableStruct(int state) { this.state = state; }

    public void ChangeState() { this.state++; }
}

struct ImmutableStruct
{
    private readonly int state;

    public MutableStruct(int state) { this.state = state; }

    public ImmutableStruct ChangeState()
    {
        return new ImmutableStruct(this.state + 1);
    }
}

[To be continued...]

Score: 1

To define whether a type is mutable or immutable, one 58 must define what that "type" is referring 57 to. When a storage location of reference 56 type is declared, the declaration merely 55 allocates space to hold a reference to an 54 object stored elsewhere; the declaration 53 does not create the actual object in question. Nonetheless, in 52 most contexts where one talks about particular 51 reference types, one will not be talking 50 about a storage location which holds a reference, but rather the object identified by that reference. The fact that one 49 can write to a storage location holding 48 a reference to an object implies in no way 47 that the object itself is mutable.

By contrast, when 46 a storage location of value type is declared, the 45 system will allocate within that storage 44 location nested storage locations for each 43 public or private field held by that value 42 type. Everything about the value type is 41 held in that storage location. If one defines 40 a variable foo of type Point and its two fields, X and 39 Y, hold 3 and 6 respectively. If one defines 38 the "instance" of Point in foo as being the pair 37 of fields, that instance will be mutable if and 36 only if foo is mutable. If one defines an 35 instance of Point as being the values held in those 34 fields (e.g. "3,6"), then such an instance 33 is by definition immutable, since changing 32 one of those fields would cause Point to hold 31 a different instance.

I think it is more 30 helpful to think of a value type "instance" as 29 being the fields, rather than the values 28 they hold. By that definition, any value 27 type stored in a mutable storage location, and 26 for which any non-default value exists, will 25 always be mutable, regardless of how it is declared. A 24 statement MyPoint = new Point(5,8) constructs a new instance of 23 Point, with fields X=5 and Y=8, and then mutates MyPoint by 22 replacing the values in its fields with 21 those of the newly-created Point. Even if a 20 struct provides no way to modify any of 19 its fields outside its constructor, there 18 is no way a struct type can protect an instance 17 from having all of its fields overwritten 16 with the content of another instance.

Incidentally, a 15 simple example where a mutable struct can 14 achieve semantics not achievable via other 13 means: Assuming myPoints[] is a single-element array 12 which is accessible to multiple threads, have 11 twenty threads simultaneously execute the 10 code:

Threading.Interlocked.Increment(myPoints[0].X);

If myPoints[0].X starts out equal to zero and twenty 9 threads perform the above code, whether 8 simultaneously or not, myPoints[0].X will equal twenty. If 7 one were to attempt to mimic the above code 6 with:

myPoints[0] = new Point(myPoints[0].X + 1, myPoints[0].Y);

then if any thread read myPoints[0].X between the 5 time another thread read it and wrote back 4 the revised value, the results of the increment 3 would be lost (with the consequence that 2 myPoints[0].X could arbitrarily end up with any value 1 between 1 and 20.

Score: 0

Objects/Structs are immutable when they 8 are passed into a function in such a way 7 as the data cannot be changed, and the returned 6 struct is a new struct. The classic example 5 is

String s = "abc";

s.toLower();

if the toLower function is written so they a 4 new string is returned that replaces "s", it's 3 immutable, but if the function goes letter 2 by letter replacing the letter inside "s" and 1 never declaring a "new String", it is mutable.

More Related questions