A few weeks ago, I discovered that strings in C# are defined as reference types and not value types. Initially I was confused about this, but then after some reading, I suddenly understood why it is important to store strings on the heap and not the stack – because it would be very inefficient to have a very large string that gets copied over an unpredictable number of stack frames. I completely accept this.
I feel that my understanding is almost complete, but there is one element that I am missing – what language feature do strings use to keep them immutable? To illustrate with a code example:
string valueA = "FirstValue";
string valueB = valueA;
valueA = "AnotherValue";
Assert.AreEqual("FirstValue", valueB); // Passes
I do not understand what language feature makes a copy of valueA when I assign it to valueB. Or perhaps, the reference to valueA does not change when I assign it to valueB, only valueA gets a new reference to itself when I set the string. As this is an instance type, I do not understand why this works.
I understand that you can overload, for example, the == and != operators, but I cannot seem to find any documentation on overloading the = operators. What is the explanation?
It is not a language feature. It is the way the class is defined.
For example,
is like an
intexcept it’s a reference type, but it’s immutable. We defined it to be so. We can define it to be mutable too:See?
It doesn’t copy the
string, it copies the reference.strings are reference type. This means that variables of typestrings are storage locations whose values are references. In this case, their values are references to instances ofstring. When you assign a variable of typestringto another of typestring, the value is copied. In this case, the value is a reference and it is copied by the assignment. This is true for any reference type, not juststringor only immutable reference types.Nope, the values of
valueAandvalueBrefer to the same instance ofstring. Their values are references, and those values are equal. If you could somehow mutate* the instance ofstringreferred to byvalueA, the referrent of bothvalueAandvalueBwould see this mutation.There is no such thing as an instance type.
Basically,
strings are reference types. Butstringare immutable. When you mutate astring, what happens is that you get a reference to a new string that is the result of the mutation to the already existingstring.Here,
sandtare variables whose values refer to the same instance ofstring. The referrent ofsis not mutated by the call toString.ToUpper. Instead,s.ToUppermakes a mutation of the referrent ofsand returns a reference to a new instance ofstringthat it creates in the process of apply the mutation. We assign that reference tou.You can’t overload
=.* You can, with some tricks. Ignore them.