Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does it make sense to copy an immutable type?

Does it make sense to implement a copy method on an immutable type, returning a new instance? Or should it just be the current instance?

I thought the type doesn't change anyway so why copy? Like no one copies the number 5, right?

like image 415
Joan Venge Avatar asked Jun 06 '09 19:06

Joan Venge


People also ask

Why is deep copy important for immutability?

Deep copying offers us true object immutability. We can change any value in an object—no matter how deeply nested it is—and it won't mutate the data we copied it from.

Why immutable objects do not require a copy constructor?

The other object creates a new immutable instance of the class and the two objects are unaffiliated. For the same reason, an immutable does not need a copy constructor when copying an object.

In which situations is it better to use an immutable object?

Immutable objects can be useful in multi-threaded applications. Multiple threads can act on data represented by immutable objects without concern of the data being changed by other threads. Immutable objects are therefore considered more thread-safe than mutable objects.

Why would you want an immutable object?

Immutable objects are thread-safe so you will not have any synchronization issues. Immutable objects are good Map keys and Set elements, since these typically do not change once created. Immutability makes it easier to parallelize your program as there are no conflicts among objects.


1 Answers

There are certain cases where it makes sense. Java strings are a good example. When a string is created in Java, it has a reference to a backing array of characters (a char[]). It knows the offset into the char array, and the length of the string. When you create a substring, that refers to the same backing array. Now consider this code:

String x = buildVeryLongString();
String y = x.substring(0, 5);
// Use y a lot, but x is garbage collected

The fact that y is still in the system means that the original char[] used by x is still required. In other words, you're using more memory than you have to. If you change the code to:

String x = buildVeryLongString();
String y = new String(x.substring(0, 5));

then you'll end up copying the data to a new char[]. When x and y have rougly the same lifetimes this approach wastes memory (by having two copies) but in the case where x is garbage collected before y, it can make a big difference.

I've run into a similar example with strings in real life, when reading words from a dictionary. By default, BufferedReader.readLine() will use a buffer of 80 characters for a line to start with - so any (non-empty) string returned by readLine() will refer to a char[] array of at least 80 characters. If you're reading a dictionary file with one word per line, that's a lot of wasted space!

This is just an example, but it shows the difference between two immutable objects which are semantically equivalent in terms of what you do with them, but have different characteristics in other ways. That is usually at the heart of why you'd want to copy an immutable type - but it's still a pretty rare thing to want to do.

In .NET, strings are stored somewhat differently - the character data is held within the string object itself instead of in a separate array. (Arrays, strings and IntPtr are the only variable-size types in .NET, as far as I'm aware.) However, the "buffer" in the string can still be larger than it needs to be. For example:

StringBuilder builder = new StringBuilder(10000);
builder.Append("not a lot");
string x = builder.ToString();

The string object referred to by x will have a huge buffer. Changing the last line to builder.ToString().Copy() would make the large buffer eligible for garbage collection immediately, leaving a small string instead. Again, doing this unconditionally is a bad idea, but it can be helpful in some cases.

like image 101
Jon Skeet Avatar answered Nov 15 '22 03:11

Jon Skeet