Thursday, December 26, 2013

Why Strings Are Mutable in Ruby

Objects can be either mutable or immutable. Mutable objects are objects whose states can be changed, while immutable objects are objects whose states never change after creation. One important implication of immutable objects are any modification of existing objects results in new objects.

Immutable objects has many desirable properties.

  • Immutable objects are thread-safe. Since any modification of existing objects results in creating new one, there is no need to set up lock to avoid conflicts while multiple threads attempt to access the object at the same time. 
  • Immutable objects make good hash keys, because the value of the hash key should never change. 
  • Immutable objects have higher memory efficiency, because the same object can be pointed to by multiple variables, thus enhancing reusability. 
Why Ruby does not adopt immutable string if it has so many advantages? The reason is it is intuitive to think of string as mutable, because you can do so many operations on a string, concatenation, appending etc. Ruby thus makes string mutable by default at the expense of performance. 

For example, appending on a string didn't creating new string.

> a = 'Hello'
=> "Hello" 
> a.object_id
=> 70161220331780 
> a << ' world!'
=> "Hello world!" 
> a.object_id
=> 70161220331780 # object_id does not change!

Don't confuse the code above with the following code

> a = 'Hello'
=> "Hello" 
> a.object_id
=> 70161220396780 
> a += ' world!'
=> "Hello world!" 
> a.object_id
=> 70161220412700 

As  "+=" creates a new string and then assign it to "a". The old string is not changed. You can make a string as immutable by using the method "freeze". After you freeze a string, an attempt to change it results in RuntimeError.

> a = 'Hello'
 => "Hello" 
> a.freeze
 => "Hello" 
> a << ' world!'
RuntimeError: can't modify frozen String

Why we need "freeze". What if we don't have it. Then we can't use string as hash key in Ruby. Because if you change the value of the string, you can't use the old value to refer to the right position in the hash. Here is how Ruby deal with it. It copies the string, freezes the copy and use the copy as the hash key.

No comments:

Post a Comment