Last Friday, my and my colleagues were discussing structs vs classes. I said that that a struct can be made immutable and that is one difference from a class. They did not agree with me in this and said that both classes and structs can be made immutable by building them immutable (by having only read only members) but there is not language support for immutable objects. I on the other hand thought that since struct is a value type, making a struct object read only should make it immutable. It cannot be changed. But a class on the other hand is a reference type and thus a class object that is read only should be possible to change the contents of but not the reference itself. This would mean that there is language support in C# for immutable struct objects but not immutable class objects. Or to be vclear, this is not only a discussion about immutabilityu but also on how const and readonly affects struct and class.
But they persisted and said that I was wrong and after a while I gave up on i, since they are better at coding than me. But it didn’t seem to be corrects what they said. So now I had to write some code now to try it out. Here we go:
(non compiling code is commented out and the compiler message is written above)
1: public class TheClass
2: {
3: public TheClass(int x, int y)
4: {
5: _x = x;
6: _y = y;
7: }
8:
9: public int _x;
10: public int _y;
11: }
12:
13:
14: struct TheStruct
15: {
16: public TheStruct(int x, int y)
17: {
18: _x = x;
19: _y = y;
20: }
21:
22: public int _x;
23: public int _y;
24: }
25:
26: class Client
27: {
28: readonly TheStruct theStruct = new TheStruct(1, 2);
29: readonly TheClass theClass = new TheClass(1, 2);
30:
31: void ModifyStruct()
32: {
33: // Members of readonly field 'TheTestLib.Client.theStruct' cannot be modified (except in a constructor or a variable initializer)
34: // theStruct._x = 15;
35:
36: // A readonly field cannot be assigned to (except in a constructor or a variable initializer)
37: // theStruct = new MyStruct(7, 18);
38:
39: // this works fine
40: theClass._x = 15;
41: theClass._y = 66;
42:
43: // A readonly field cannot be assigned to (except in a constructor or a variable initializer)
44: // theClass = new MyClass(7, 18);
45: }
46: }
So. It turned out that by declaring your struct object readonly it becomes read only You cannot change the contents and you cannot change the object. The class on the other hand behaved as I expected. You can change the contents, but not the reference. This does not however mean that it is immutable since it is ok to do this:
We add this method to the struct:
public void IncreaseX()
{
_x++;
}
And then try to call it from our client.
theStruct.IncreaseX();
this work fine. So the objects it read only, but it can change itself. Not immutable. How about const? Can we use that? While readonly gives you runt time read only, const gives you compile time read only. We get the compiler error
"The type 'TheTestLib.MyStruct' cannot be declared const".
Just for completeness we can try to use const on the class. This does not work either, we get the error:
"A const field of a reference type other than string can only be initialized with null."
So to me it looks like we do not have any language support for immutability in C# with one clear keywor. But you have to build immutable classes adn structs, by using patterns. Like when building singletons for example. And I also learned some about the different behaviour of structs vs classes.
Please comment if you find any errors or if you have anything to add.