Why are C # structures immutable?

I was just curious to know why structures, strings, etc. immutable? What is the reason that they become unchanged, and the rest of the objects are changed. What are the things that are believed to make an object immutable?

Is there a difference in the methods of allocating and freeing memory for mutable and immutable objects?

+50
immutability c #
Sep 20 '10 at 13:28
source share
5 answers

If this topic interests you, I have a number of articles on immutable programming at http://blogs.msdn.com/b/ericlippert/archive/tags/immutability/

I was just curious to know why structures, strings, etc. immutable?

Structures and classes are not immutable by default, although it is best to make structures immutable. I also like immutable classes.

Lines are immutable.

What is the reason for their immutability and the rest of the objects as mutable.

Reasons to make all types immutable:

  • It's easier to talk about objects that don't change. If I have a line with three elements in it, I know that it is not empty, it was not empty five minutes ago, it will not be empty in the future. It is immutable! As soon as I find out about this fact, I can use this fact forever. Facts about immutable objects do not become obsolete.

  • A special case of the first point: immutable objects are much easier to make thread safe. Most thread safety concerns relate to writing on one thread and reading on another; immutable objects have no records.

  • Immutable objects can be split and reused. For example, if you have an immutable binary tree, you can use its left and right subtrees as subtrees of another tree without worrying about it. In a mutable structure, you usually make copies of the data for reuse, because you do not want changes to one logical entity affect another. This can save a lot of time and memory.

Reasons for Creating Immutable Structures

There are many reasons to make structures unchanged. Here is just one.

Structures are copied by value, not by reference. It is easy to accidentally treat the structure as copied by reference. For example:

void M() { S s = whatever; ... lots of code ... s.Mutate(); ... lots more code ... Console.WriteLine(s.Foo); ... } 

Now you want to refactor part of this code into a helper method:

 void Helper(S s) { ... lots of code ... s.Mutate(); ... lots more code ... } 

WRONG! It should be (ref S s) - if you do not, then the mutation will occur on copy s. If you do not allow mutations in the first place, all these problems disappear.

Reasons for immutable strings

Remember my first moment about facts about immutable structures that remain facts?

Suppose the line is changed:

 public static File OpenFile(string filename) { if (!HasPermission(filename)) throw new SecurityException(); return InternalOpenFile(filename); } 

What if the hostile caller changes the file name after a security check and before opening the file? The code simply opened a file to which they may not have permission!

Again, mutable data is hard to justify. You want "this caller to have the right to see that the file described by this line" is true forever until a mutation occurs. With the modified lines, in order to write protected code, we constantly had to make copies of the data, which, as we know, do not change.

What are the things that are believed to make an object immutable?

Is a type logically representing something that is an β€œeternal” value? The number 12 is the number 12; he does not change. Integers must be immutable. Point (10, 30) is point (10, 30); he does not change. Points must be unchanged. The string "abc" is the string "abc"; he does not change. Lines must be immutable. The list (10, 20, 30) does not change. And so on.

Sometimes a type represents things that change. Last Name Mary Smith - Smith, but tomorrow she may be Mary Jones. Or Miss Smith today may be Dr. Smith tomorrow. The alien has fifty health points, but he has ten after being hit by a laser beam. Some things are best represented as mutations.

Is there a difference in the methods of allocating and freeing memory for mutable and immutable objects?

Not as such. As I mentioned earlier, one of the nice things about fixed values ​​is that you can reuse portions of them without copying. Therefore, in this sense, the distribution of memory can be very different.

+106
Sep 20 '10 at 16:55
source share

Not structured ... that's why mutable structures are evil.

Creating mutable structures can lead to all kinds of weird behavior in your application, and therefore they are considered very bad ideas (stemming from the fact that they look like a reference type, but are actually a value type and will be copied when you pass them).

There are strings, on the other hand. This makes them inherently thread safe, and also allows optimization by string interning. If you need to build a complex string on the fly, you can use StringBuilder .

+9
Sep 20 '10 at 13:30
source share

The concepts of variability and immutability have different meanings when applied to structures and classes. A key aspect (often a key weakness) of mutable classes is if Foo has a Bar field of type List<Integer> that contains a link to a list containing (1,2,3), another code that has a link to the same list can change him, so Bar contains a link to a list containing (4,5,6), even if this other code does not have access to Bar . In contrast, if Foo has a Biz field of type System.Drawing.Point , the only way to change any aspect of Biz is to have write access to that field.

The fields (public and private) of the structure can be mutated by any code that can mutate the location of the storage in which the structure is stored, and cannot be changed by any code that cannot mutate the storage location in which it is stored. If all the information encapsulated within a structure is stored in its fields, such a structure can effectively combine immutable type management with the convenience of a mutable type if the structure is not encoded in such a way as to remove such convenience (for example, a habit that, unfortunately, some programmers recommend Microsoft).

The β€œproblem” with structs is that when a method (including the implementation of a property) is called in a structure in a read-only context (or immutable location), the system copies the structure, executes the method on a temporary copy, and silently discards the result. As a result, programmers have put forward the unfortunate opinion that a way to avoid problems using mutating methods is that many structures do not allow piecewise updates when problems could be avoided by simply replacing properties with open fields.

By the way, some people complain that when a class property returns a conveniently modifiable structure, changes in the structure do not affect the class from which it came. I would say that the good thing is the fact that the returned element is a structure makes the behavior understandable (especially if it is an open field structure). Compare the fragment using a hypothetical structure and property on Drawing.Matrix , using the actual property of this class implemented by Microsoft:

 // Hypothetical struct
 public struct {
   public float xx, xy, yx, yy, dx, dy;
 } Transform2d;

 // Hypothetical property of "System.Drawing.Drawing2d.Matrix"
 public Transform2d Transform {get;}

 // Actual property of "System.Drawing.Drawing2d.Matrix"
 public float [] Elements {get;  }

 // Code using hypothetical struct
 Transform2d myTransform = myMatrix.Transform;
 myTransform.dx + = 20;
 ... other code using myTransform

 // Code using actual Microsoft property
 float [] myArray = myMatrix.Elements;
 myArray [4] + = 20;
 ... other code using myArray

Looking at the actual Microsoft property, is there a way to determine if writing to myArray[4] will affect myMatrix ? Even looking at the page http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.matrix.elements.aspx is there any way to tell? If the property was written using the structural equivalent, there would be no confusion; a property that returns a structure will return no more than the current value of six numbers. Changing myTransform.dx would be nothing more than writing to a floating-point variable that is not bound to anything else. Anyone who doesn't like the fact that changing myTransform.dx does not affect myMatrix should be just as annoyed that writing myArray[4] does not affect myMatrix , except that the independence of myMatrix and myTransform obvious, and the independence of myMatrix and myArray not that.

+3
Oct 10 '12 at 17:03
source share

The type of structure is not immutable. Yes, there are lines. Making your own type immutable is easy, just do not provide a default constructor, make all fields private, and do not define any methods or properties that change the value of the field. Have a method that should mutate an object, instead return a new object. There is an angle of memory management, you usually create a lot of copies and garbage.

+2
Sep 20 '10 at 13:43
source share

Structures can be volatile, but this is a bad idea because they have copy semantics. If you make changes to the structure, you can really change the copy. Keeping track of what has been changed is very difficult.

Sane structures cause errors.

+1
Sep 20 '10 at 13:30
source share



All Articles