Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is meant by immutable?

This could be the dumbest question ever asked but I think it is quite confusing for a Java newbie.

  1. Can somebody clarify what is meant by immutable?
  2. Why is a String immutable?
  3. What are the advantages/disadvantages of the immutable objects?
  4. Why should a mutable object such as StringBuilder be preferred over String and vice-verse?

A nice example (in Java) will be really appreciated.

like image 804
ashokgelal Avatar asked Nov 10 '08 23:11

ashokgelal


People also ask

Whats immutable means?

: not capable of or susceptible to change. Other Words from immutable Synonyms & Antonyms Did you know?

What is an example of immutable?

String is an example of an immutable type. A String object always represents the same string.

What is immutable in life?

There are many things in life that are immutable; these unchangeable things include death, taxes, and the laws of physics. The adjective immutable has Latin roots that mean "not changeable." The Latin prefix for not is in, but the spelling changes when the prefix is put before the consonant m.

Does immutable mean never changing?

Something that is immutable will never change or cannot be changed.


2 Answers

Immutable means that once the constructor for an object has completed execution that instance can't be altered.

This is useful as it means you can pass references to the object around, without worrying that someone else is going to change its contents. Especially when dealing with concurrency, there are no locking issues with objects that never change

e.g.

class Foo {      private final String myvar;       public Foo(final String initialValue)      {          this.myvar = initialValue;      }       public String getValue()      {          return this.myvar;      } } 

Foo doesn't have to worry that the caller to getValue() might change the text in the string.

If you imagine a similar class to Foo, but with a StringBuilder rather than a String as a member, you can see that a caller to getValue() would be able to alter the StringBuilder attribute of a Foo instance.

Also beware of the different kinds of immutability you might find: Eric Lippert wrote a blog article about this. Basically you can have objects whose interface is immutable but behind the scenes actual mutables private state (and therefore can't be shared safely between threads).

like image 158
Douglas Leeder Avatar answered Sep 20 '22 19:09

Douglas Leeder


An immutable object is an object where the internal fields (or at least, all the internal fields that affect its external behavior) cannot be changed.

There are a lot of advantages to immutable strings:

Performance: Take the following operation:

String substring = fullstring.substring(x,y); 

The underlying C for the substring() method is probably something like this:

// Assume string is stored like this: struct String { char* characters; unsigned int length; };  // Passing pointers because Java is pass-by-reference struct String* substring(struct String* in, unsigned int begin, unsigned int end) {     struct String* out = malloc(sizeof(struct String));     out->characters = in->characters + begin;     out->length = end - begin;     return out; } 

Note that none of the characters have to be copied! If the String object were mutable (the characters could change later) then you would have to copy all the characters, otherwise changes to characters in the substring would be reflected in the other string later.

Concurrency: If the internal structure of an immutable object is valid, it will always be valid. There's no chance that different threads can create an invalid state within that object. Hence, immutable objects are Thread Safe.

Garbage collection: It's much easier for the garbage collector to make logical decisions about immutable objects.

However, there are also downsides to immutability:

Performance: Wait, I thought you said performance was an upside of immutability! Well, it is sometimes, but not always. Take the following code:

foo = foo.substring(0,4) + "a" + foo.substring(5);  // foo is a String bar.replace(4,5,"a"); // bar is a StringBuilder 

The two lines both replace the fourth character with the letter "a". Not only is the second piece of code more readable, it's faster. Look at how you would have to do the underlying code for foo. The substrings are easy, but now because there's already a character at space five and something else might be referencing foo, you can't just change it; you have to copy the whole string (of course some of this functionality is abstracted into functions in the real underlying C, but the point here is to show the code that gets executed all in one place).

struct String* concatenate(struct String* first, struct String* second) {     struct String* new = malloc(sizeof(struct String));     new->length = first->length + second->length;      new->characters = malloc(new->length);      int i;      for(i = 0; i < first->length; i++)         new->characters[i] = first->characters[i];      for(; i - first->length < second->length; i++)         new->characters[i] = second->characters[i - first->length];      return new; }  // The code that executes struct String* astring; char a = 'a'; astring->characters = &a; astring->length = 1; foo = concatenate(concatenate(slice(foo,0,4),astring),slice(foo,5,foo->length)); 

Note that concatenate gets called twice meaning that the entire string has to be looped through! Compare this to the C code for the bar operation:

bar->characters[4] = 'a'; 

The mutable string operation is obviously much faster.

In Conclusion: In most cases, you want an immutable string. But if you need to do a lot of appending and inserting into a string, you need the mutability for speed. If you want the concurrency safety and garbage collection benefits with it the key is to keep your mutable objects local to a method:

// This will have awful performance if you don't use mutable strings String join(String[] strings, String separator) {     StringBuilder mutable;     boolean first = true;      for(int i = 0; i < strings.length; i++)     {         if(!first) first = false;         else mutable.append(separator);          mutable.append(strings[i]);     }      return mutable.toString(); } 

Since the mutable object is a local reference, you don't have to worry about concurrency safety (only one thread ever touches it). And since it isn't referenced anywhere else, it is only allocated on the stack, so it is deallocated as soon as the function call is finished (you don't have to worry about garbage collection). And you get all the performance benefits of both mutability and immutability.

like image 40
Imagist Avatar answered Sep 20 '22 19:09

Imagist