Immutable VS Mutable Types

Which types are mutable and immutable in the Google Go Language?

Don't worry -- Go will let you shoot yourself in the foot if you really want to :-)

Go is not like Erlang, which might be what you are getting at with the question.

x := 1
x = 2

allocates one variable, x, with a value of 1, then reassigns it to 2 -- no additional memory is allocated here.

As you note, strings are immutable, so doing a string manipulation can result in making copies. If you find that you want to do in-place modifications to character data, you'll probably want to operate on variables of []byte via the bytes package.

Russ Cox's post about this should answer most of your questions about basic data structures:

As other commenters noted, you'll want to look at the value semantics of Go functions -- they might be a little surprising at first.

If you have the following function:

func (t MyType) myFunc() {
// do something to set a field in t

and you call in your code


you might be surprised to see that this doesn't do what you want because the t that is seen in myFunc() is really a copy of myVar.

But, the following will work:

func (t *myType) myFunc() {
// do something to set a field in t

because the function has a copy of the pointer and can access the underlying structure via that pointer.

Mutable vs immutable objects

Well, there are a few aspects to this.

  1. Mutable objects without reference-identity can cause bugs at odd times. For example, consider a Person bean with a value-based equals method:

    Map<Person, String> map = ...
    Person p = new Person();
    map.put(p, "Hey, there!");

    map.get(p); // => null

    The Person instance gets "lost" in the map when used as a key because its hashCode and equality were based upon mutable values. Those values changed outside the map and all of the hashing became obsolete. Theorists like to harp on this point, but in practice I haven't found it to be too much of an issue.

  2. Another aspect is the logical "reasonability" of your code. This is a hard term to define, encompassing everything from readability to flow. Generically, you should be able to look at a piece of code and easily understand what it does. But more important than that, you should be able to convince yourself that it does what it does correctly. When objects can change independently across different code "domains", it sometimes becomes difficult to keep track of what is where and why ("spooky action at a distance"). This is a more difficult concept to exemplify, but it's something that is often faced in larger, more complex architectures.

  3. Finally, mutable objects are killer in concurrent situations. Whenever you access a mutable object from separate threads, you have to deal with locking. This reduces throughput and makes your code dramatically more difficult to maintain. A sufficiently complicated system blows this problem so far out of proportion that it becomes nearly impossible to maintain (even for concurrency experts).

Immutable objects (and more particularly, immutable collections) avoid all of these problems. Once you get your mind around how they work, your code will develop into something which is easier to read, easier to maintain and less likely to fail in odd and unpredictable ways. Immutable objects are even easier to test, due not only to their easy mockability, but also the code patterns they tend to enforce. In short, they're good practice all around!

With that said, I'm hardly a zealot in this matter. Some problems just don't model nicely when everything is immutable. But I do think that you should try to push as much of your code in that direction as possible, assuming of course that you're using a language which makes this a tenable opinion (C/C++ makes this very difficult, as does Java). In short: the advantages depend somewhat on your problem, but I would tend to prefer immutability.

Explain the difference between mutable and immutable

A mutable object can be mutated or changed. An immutable object cannot. For example, while you can add or remove objects from an NSMutableArray, you cannot do either with an NSArray.

Mutable objects can have elements changed, added to, or removed, which cannot be achieved with immutable objects. Immutable objects are stuck with whatever input you gave them in their [[object alloc] initWith...] initializer.

The advantages of your mutable objects is obvious, but they should only be used when necessary (which is a lot less often than you think) as they take up more memory than immutable objects.

Mutable and Immutable in Python

You really shouldn't see the same ID twice in a row, but CPython has an optimization for string concatenation with + that doesn't quite obey all the rules it's supposed to.

When CPython sees an operation of the form x = x + something or x += something, if x refers to a string and x holds the only reference to that string, then CPython will grow the string with realloc instead of creating a new string object. Depending on details of available memory, realloc may resize the allocated memory in place, or it may allocate new memory. If it resizes the allocation, the object's id remains the same. You can see the implementation in unicode_concatenate in Python/ceval.c.

This optimization is mostly fine, because the refcount check ensures it behaves mostly as if strings were really immutable and a new string was created. However, in x = x + stuff, the old string and the new string should have briefly overlapping lifetimes, because the new string should come into existence before the assignment ends the old string's lifetime, so it should be impossible for the ID values to be equal.

id is one of the few ways the optimization is observably different from if no string mutation occurred. The language developers seem to have decided they're okay with that.

mutable objects changed in-place means what?

In Python a variable holds a reference to an object.

To "change" a variable, you may either change the referenced object. Or reference an other object.

"Immutable" object force you to use the first solution as the object by itself cannot be modified. "Mutable" objects give you the choice between the two options.

As string are immutable, you cannot "change" a string object. All you can do, is create a new string and update the reference to hold that newly created string:

>>> v1 = v2 = "hello"
>>> v1 += "world"

# v1 and v2 no longer references the same object:
>>> v1 is v2

>>> v1
>>> v2

But as list are mutable you have the choice to change them "in place":

>>> v1 = v2 = ['h', 'e', 'l', 'l', 'o']
>>> v1 += ['w', 'o', 'r', 'l', 'd']

# v1 and v2 still references the same object:
>>> v1 is v2

>>> v1
['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']
>>> v2
['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']

Or to create a new list and update the reference:

>>> v1 = v2 = ['h', 'e', 'l', 'l', 'o']
>>> v1 = v1 + ['w', 'o', 'r', 'l', 'd']

# v1 and v2 no longer references the same object:
>>> v1 is v2

>>> v1
['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']
>>> v2
['h', 'e', 'l', 'l', 'o']

Global on mutable vs immutable

global has nothing to do with mutability. It changes the scope of a name, whether the global refers to a mutable or immutable object, so that you can assign a different value to the name.

When assigning to a global name, the old value may or may not have been mutable, and the new value can be either as well.

d = {}
e = 6

def change():
global d, e
d = 3
e = []

Related Topics

Leave a reply