Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

It seems that thread-safety is always/often mentioned as the main benefit of using immutable types and especially collections.

I have a situation where I would like to make sure that a method will not modify a dictionary of strings (which are immutable in C#). I’d like to constrain things as much as possible.

However I am not sure whether adding a dependency to a new package (Microsoft Immutable Collections) is worth it. Performance is not a big issue either.

So I guess my question is whether immutable collections are strongly advised for when there are no hard performance requirements and there are no thread safety issues? Consider that value semantics (as in my example) might or might not be a requirement as well.

share|improve this question
1  
Concurrent modification need not mean threads. Just look at the aptly named ConcurrentModificationException which is usually caused by the same thread mutating the collection in the same thread, in the body of a foreach loop over the same collection. –  delnan Jul 24 at 12:35
1  
I mean you aren't wrong, but that is different than what OP is asking. That exception is thrown because modification during enumeration is not allowed. Using a ConcurrentDictionary, for example, would still have this error. –  edthethird Jul 24 at 15:50
12  
Maybe you should also ask yourself the opposite question: when is mutability worthwhile? –  Giorgio Jul 24 at 16:08
2  
In Java, if mutability affects hashCode() or equals(Object) result being changed, it may cause errors when using Collections (for example, in a HashSet the object was stored in a "bucket" and after mutating it should go to another one). –  SJuan76 Jul 25 at 21:33
2  
@DavorŽdralo As far as high level languages' abstractions go, pervasive immutability is rather tame. It is just a natural extension of the very common abstraction (present even in C) of creating, and silently discarding, "temporary values". Perhaps you mean to say it's an inefficient way to use a CPU, but that argument has flaws too: Mutability-happy but dynamic languages often perform worse than immutable-only but static languages, partly because there are some clever (but ultimately quite simple) tricks to optimize programs juggling immutable data: Linear types, deforestation, etc. –  delnan Jul 26 at 13:02

8 Answers 8

up vote 92 down vote accepted

Immutability simplifies the amount of information you need to track mentally when reading code later. For mutable variables, and especially mutable class members, it's very hard to know what state they will be in at the specific line you're reading about, without running through the code with a debugger. Immutable data is easy to reason about - it will always be the same. If you want to change it, you need to make a new value.

I would honestly prefer making things immutable by default, and then changing them to mutable where it's proven that they need to be, whether this means you need the performance, or an algorithm you have doesn't make sense for immutability.

share|improve this answer
20  
+1 Concurrency is simultaneous mutation, but mutation that spreads over time can be just as hard to reason about –  guillaume31 Jul 24 at 12:29
18  
To expand on this: a function that relies on a mutable variable can be thought of as taking an extra hidden argument, which is the current value of the mutable variable. Any function which changes a mutable variable can likewise be thought of as producing an extra return value, i.e. the new value of the mutable state. When looking at a piece of code you have no idea if it depends on or changes mutable state so you have to find out and then keep track of the changes mentally. This also introduces coupling between any two pieces of code that share mutable state, and coupling is bad. –  Doval Jul 24 at 12:29
26  
@Mehrdad People also managed to crank out large programs in assembly for decades. Then we did a couple of decades of C. –  Doval Jul 24 at 12:46
11  
@Mehrdad Copying whole objects isn't a good option when the objects are large. I don't see why the order of magnitude involved in the improvement matters. Would you turn down a 20% improvement (note: arbitrary number) in productivity simply because it wasn't a triple-digit improvement? Immutability is a sane default; you can stray from it, but you need a reason. –  Doval Jul 24 at 13:04
9  
@Giorgio Scala made me realize just how infrequently you need to even make a value mutable. Whenever I use that language, I make everything a val, and only on very, very rare occasions do I find that I need to change something into a var. A lot of the 'variables' I define in any given language are just there to hold a value that stores the result of some computation, and doesn't need to be updated. –  KChaloux Jul 24 at 14:28

Your code should express your intention. If you don't want an object to be modified once created, make it impossible to modify.

Immutability has several benefits:

  • The intention of the original author is expressed better.

    How would you be able to know that in the following code, modifying the name would cause the application to generate an exception somewhere later?

    public class Product
    {
        public string Name { get; set; }
    
        ...
    }
    
  • It's easier to make sure that the object wouldn't appear in an invalid state.

    You have to control this in a constructor, and only there. On the other hand, if you have a bunch of setters and methods which modify the object, such controls may become particularly difficult, especially when, for example, two fields should change at the same time in order for the object to be valid.

    For example, an object is valid if the address is not null or GPS coordinates are not null, but it's invalid if both the address and the GPS coordinates are specified. Can you imagine the hell to validate this if both the address and GPS coordinates have a setter, or both are mutable?

  • Concurrency.

By the way, in your case, you don't need any third party packages. .NET Framework already includes a ReadOnlyDictionary<TKey, TValue> class.

share|improve this answer
1  
+1, especially for "You have to control this in a constructor, and only there." IMO this is a huge advantage. –  Giorgio Jul 24 at 14:25
9  
Another benefit: copying an object is free. Just a pointer. –  Robert Grant Jul 24 at 15:19
1  
@MainMa Thank you for your answer, but as far as I understand ReadOnlyDictionary doesn't give any guarantees that someone else will not change the underlying dictionary (even without concurrency I might want to save the reference to the original dictionary within object the method belongs to for later use). ReadOnlyDictionary is even declared in a strange namespace: System.Collections.ObjectModel. –  Den Jul 24 at 15:58
2  
@Den: That relates to one of my pet peeves: people regarding "read-only" and "immutable" as synonyms. If an object is encapsulated in a read-only wrapper and no other reference exists or is retained anywhere in the universe then wrapping the object will make it immutable, and a reference to the wrapper may be used as a shorthand to encapsulate the state of the object contained therein. There is, however, no mechanism by which code can ascertain whether that is the case. To the contrary, because the wrapper hides the type of the wrapped object, wrapping an immutable object... –  supercat Jul 25 at 15:38
2  
...will make it impossible for code to know whether the resulting wrapper may be safely considered immutable. –  supercat Jul 25 at 15:39

There are many single-threaded reasons to use immutability. For example

Object A contains Object B.

External code queries your Object B and you return it.

Now you have three possible situations:

  1. B is immutable, no problem.
  2. B is mutable, you make a defensive copy and return that. Performance hit but no risk.
  3. B is mutable, you return it.

In the third case the user code may not realize what you have done and may make changes to the object, and by so doing change the internal data of your object with you having no control or visibility of that happening.

share|improve this answer

Immutability can also greatly simplify the implementation of garbage collectors. From GHC's wiki:

[...] Data immutability forces us to produce a lot of temporary data but it also helps to collect this garbage rapidly. The trick is that immutable data NEVER points to younger values. Indeed, younger values don't yet exist at the time when an old value is created, so it cannot be pointed to from scratch. And since values are never modified, neither can it be pointed to later. This is the key property of immutable data.

This greatly simplifies garbage collection (GC). At anytime we can scan the last values created and free those that are not pointed to from the same set (of course, real roots of live values hierarchy are live in the stack). [...] So it has a counter-intuitive behavior: the larger percent of your values are garbage - the faster it works. [...]

share|improve this answer

Expanding on what KChaloux summarised very well...

Ideally, you have two types of fields, and hence two types of code using them. Either fields are immutable, and code doesn't have to take mutability into account; or fields are mutable, and we need to write code that either takes a snapshot (int x = p.x) or gracefully handles such changes.

In my experience, most code falls in between the two, being optimistic code: it freely references mutable data, assuming that the first call to p.x will have the same result as the second call. And most of the time, this is true, except when it turns out it no longer is. Oops.

So, really, turn that question around: What are my reasons for making this mutable?

  • Reducing memory alloc/free?
  • Mutable by nature? (e.g. counter)
  • Saves modifiers, horizontal noise? (const/final)
  • Makes some code shorter/easier? (init default, possibly overwrite after)

Do you write defensive code? Immutability will save you some copying around. Do you write optimistic code? Immutability will spare you the insanity of that weird, impossible bug.

share|improve this answer

Another benefit of immutability is that it is the first step in rounding up these immutable objects into a pool. Then you can manage them so that you don't create multiple objects that conceptually and semantically represent the same thing. A good example would be Java's String.

It is a well-known phenomenon in linguistic that a few words appear a lot, might appear in other context as well. So instead of creating multiple String object, you can use one immutable. But then you need to keep a pool manager to take care of these immutable objects.

This will save you lot of memory. This is an interesting article to read as well: http://en.wikipedia.org/wiki/Zipf%27s_law

share|improve this answer

In Java, C#, and other similar languages, class-type fields may be used either to identify objects, or to encapsulate values or state in those objects, but the languages make no distinction between such usages. Suppose a class object George has a field of type char[] chars;. That field may encapsulate a character sequence in either:

  1. An array which will never be modified, nor exposed to any code that might modify it, but to which outside references may exist.

  2. An array to which no outside references exist, but which George may modify freely.

  3. An array which is owned by George, but to which there may exist outside views which would be expect to represent George's current state.

Additionally, the variable may, instead of encapsulating a character sequence, encapsulate a live view to a character sequence owned by some other object

If chars presently encapsulates the character sequence [w i n d], and George wants chars to encapsulate the character sequence [w a n d], there are a number of things George could do:

A. Construct a new array containing the characters [w a n d] and change chars to identify that array rather than the old one.

B. Identify somehow a pre-existing character array which will always hold the characters [w a n d] and change chars to identify that array rather than the old one.

C. Change the second character of the array identified by chars to an a.

In case 1, (A) and (B) are safe ways to achieve the desired result. In case (2), (A) and (C) are safe, but (B) would not be [it wouldn't cause immediate problems, but since George would assume that it has ownership of the array, it would assume that it could change the array at will]. In case (3), choices (A) and (B) would break any outside views, and thus only choice (C) is correct. Thus, knowing how to modify the character sequence encapsulated by the field requires knowing which semantic type of field it is.

If instead of using a field of type char[], which encapsulates a potentially-mutable character sequence, code has used type String, which encapsulates an immutable character sequence, all of the above issues go away. All fields of type String encapsulate a sequence of characters using a sharable object that will never change. Consequently, if a field of type String encapsulates "wind", the only way to make it encapsulate "wand" is to make it identify different object--one which holds "wand". In cases where code holds the only reference to the object, mutating the object may be more efficient than creating a new one, but any time a class is mutable it is necessary to distinguish among the different ways by which it can encapsulate value. Personally I think Apps Hungarian should have been used for this (I would consider the four uses of char[] to be semantically-distinct types, even though the type system considers them identical--exactly the sort of situation where Apps Hungarian shines), but since it wasn't the easiest way to avoid such ambiguities is to design immutable types that only encapsulate values one way.

share|improve this answer
    
It looks like a reasonable answer, but is a bit hard to read and comprehend. –  Den Jul 25 at 15:18

There is a lot of good answers already. This is just an extra info somewhat specific to .NET. I was digging through old .NET blog posts and found a nice sum-up of benefits from the point of view of the Microsoft Immutable Collections developers:

  1. Snapshot semantics, allowing you to share your collections in a way that the receiver can count on never changing.

  2. Implicit thread-safety in multi-threaded applications (no locks required to access collections).

  3. Any time you have a class member that accepts or returns a collection type and you want to include read-only semantics in the contract.

  4. Functional programming friendly.

  5. Allow modification of a collection during enumeration, while ensuring original collection does not change.

  6. They implement the same IReadOnly* interfaces that your code already deals with so migration is easy.

If someone hands you a ReadOnlyCollection, an IReadOnlyList, or an IEnumerable the only guarantee is that you can’t change the data – there is no guarantee that the person that handed you the collection won’t change it. Yet, you often need some confidence that it won’t change. These types don’t offer events to notify you when their contents change, and if they do change, might that occur on a different thread, possibly while you’re enumerating its contents? Such behavior would lead to data corruption and/or random exceptions in your application.

share|improve this answer

protected by maple_shaft Jul 24 at 18:48

Thank you for your interest in this question. Because it has attracted low-quality answers, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.