6

Possible Duplicate:
At what point do immutable classes become a burden?

This is something I never understood. When learning C++, for instance, I had lots of headaches with const issues, as it added lots of complexity to programming. Why is immutability important? And is it always necessary?

0

2 Answers 2

14

The glib answer is that mutability is necessary, because software that doesn't change anything is kind of pointless. Ultimately, at least some of your data is going to be mutable - even if it is just the input and output of the process.

Really, though, you are asking why you would choose to use immutable rather than mutable data in various parts of your program, and the answer to that is complexity.

Complexity is the thing that makes software difficult. Mutable data is inherently complex, because it can change.

Complexity is what makes software difficult, because it makes doing anything with it hard. It could be the complexity of doing the right thing in the face of all your state, or the complexity of concurrency, or the complexity of changing code to meet new requirements.

Ultimately, though, the simpler software is the easier it is to keep working, and to improve, over time. There is a lot of education, experience, and related discussion that most of the cost of software is really keeping it working over the full life of the software.

The reason that mutable data makes software more complex is fairly simple, if you contrast the thinking you need to do about the data:

If the data is immutable you need to know what it means, where it was first assigned, and perhaps how it is used here.

If the data is mutable you need to know what it means, where it was first assigned, where it can be changed, when it can be changed, if those changes can happen concurrently and require locks, what sequence locks need to be acquired in, if changing the data needs coordination with others, and if it is actually changed here.

There are other advantages to immutable data, such as garbage collection efficiency, lock-free operation, efficient substructure sharing, and so forth, but they are technical choices - and while they are becoming more important as multi-core processing becomes more common, they are not the heart of the advantage.

Finally, to the implicit question of why you found it so challenging in your learning the language... Obviously, I can only speculate, but in my experience there are two causes for this in people learning programming, programming languages, and programming paradigms:

The first is that most teaching problems are great tools for learning, but have very little to do with the "real world" of software engineering. At the scale of a teaching problem you probably know the entire codebase, end to end, and it is small enough you can hold a picture in your head of how it all works.

When you are working with a team of five, or ten, or fifty, or five hundred people on a codebase with a half million lines of code, where you have never even seen most of the code around what you are working on - well, then you start to appreciate immutable data, because you need to know so much less.

The second is that your comment on "added lots of complexity" mirrors what a bunch of other people have said to me. Generally, they felt it added a lot of complexity because they just wanted to write code until something worked without spending a lot of time thinking about the bigger picture of the problem.

Now, I have no idea if this is true of you or not - I never met you - but maybe it is the same thing.

Mutable data is an easy solution to "I need X to change so that Y happens" when you are in a random part of the code and need to trigger some distant effect.

That adds complexity. Not local complexity, sure, because you can more easily change the value and all. Remote complexity. Invisible complexity.

It spreads out the details of where change happens, and of where the behaviour of the system is defined. As you go down this path, and grow the size of the system, you rediscover the problems that Object Oriented analysis and design came about to combat.

Again, I don't know you, and that may have nothing to do with why you found it "added complexity", but it is the most common pattern in my experience of folks saying the same thing.

7

The argument is that immutable data has 2 advantages:

  1. You can safely access it from 2 threads without worrying about locks or other concurrency issues.

  2. In many cases it produces code that's easier to reason about, easier to test, and easier to be confident about its correctness.

For instance, the result of some function might be an object, and perhaps one of the post-conditions we want to test is the value of some property of the result object:

[Test]
public void Result_of_Foo_has_property_X_which_is_based_on_input_Y()
{
    var test = BuildObjectForTest();
    var result = test.Foo(23);
    Assert.AreEqual(15, result.X);
}

If the result object is mutable, then maybe testing property X changed the value of X, or changed some other property of the object. That's a side-effect, and we try to reduce side effects because they produce complex code. Also, depending on the internal state of the test object, perhaps calling Foo again with the same argument might not produce the same result. Programmers using this code need to know that.

If the programmer using it knows that both are immutable objects, they can greatly reduce the amount of thought they have to put into understanding it.

In my experience, there are two types of code: ones that carry out an action (print something to the screen, move the robot, update a record in the database, etc.) and there is code that answers a question. The first kind obviously has side effects because it kind of changes stuff in the real world (the stuff on the screen is replaced by new stuff, or the robot moves, or the database data is modified). The second kind should be purely functional, which is side-effect free. If I ask you to tell me what 2 + 2 is, you shouldn't have to change the value of 2 to tell me the answer is 4. Therefore, I expect that the values 2 and 4 are immutable. Likewise, I want my values a and b to be immutable, if I ask you the result of a + b.

1
  • The primary advantage of immutability is more fundamentally that a reference to an object may be seen as synonymous with the data contained therein. For languages which have limited means of passing around data without passing around Promiscuous Object References, data contained in objects whose references are synonymous with that data can be passed around much more easily than data encapsulated in other forms.
    – supercat
    May 5, 2014 at 2:35

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