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

26,966

Solution 1

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: http://research.swtch.com/2009/11/go-data-structures.html

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

myVar.myFunc()

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.

Solution 2

In my opinion, one should first separate the following two concepts:

  • integers as mathematical objects (that is: values)

  • variables of type int

Then the answer is: Integer variables are mutable, integer values are immutable.

This view is consistent with the Go specification which states that strings are immutable. Obviously, a string variable is mutable.

Variables (as a concept) in Go are at least:

  • named variables (such as: var i int)
  • variables accessible via pointers

Mutable Go objects:

  • arrays and slices
  • maps
  • channels
  • closures which are capturing at least 1 variable from the outer scope

Immutable Go objects:

  • interfaces
  • booleans, numeric values (including values of type int)
  • strings
  • pointers
  • function pointers, and closures which can be reduced to function pointers
  • structs having a single field

Go objects which some people may consider mutable, while other people may consider them immutable:

  • structs having multiple fields

Solution 3

"Mutability" only makes sense when you talk about some composite type, something that has "internal" parts, that perhaps can be changed independently of the thing that contains it. Strings are naturally composed of characters, and there is no mechanism in the language that lets us change a character in an existing string, short of assigning a whole new string, so we say that it is immutable.

For an int, it doesn't really make sense to talk about mutability, because, what are the "components" of an int? You change an int by assigning a whole new int, but assignment does not count as "mutating".

There is some connection between the issues of mutability and reference vs. value types. Semantically, there is no difference between an immutable reference type and a value type. Why? Suppose int was actually a pointer to an immutable object (i.e. *InternalIntObject with no functions for changing InternalIntObject). Once you assign such a pointer to a variable, it will forever represent the same integer value (can't be changed by others who share the same object) since the object is immutable. This is the same behavior as an integer value type. You can assign ints by assignment operator; likewise you can assign these pointers by assignment; the result would be the same: the assigned variable represents the same integer as what it was assigned to. Only difference would be the comparison and arithmetic operators would have to be re-defined to de-reference the pointer to compute the result.

Mutability is therefore only meaningful for reference types.

As for what you asked, the "mutable" types are generally considered to be the reference types except string: maps, channels, slices (with respect to the data pointed to by the slice), and also pointers to anything (since you can mutate the value at the location pointed to by the pointer).

Solution 4

Yes, the word immutable comes up exactly once in Go spec. And that's when discussing type string. I think you should look at it more from the dual view points of Assignability and Addressability. For example Go will forbid you from rebinding variable to a different value of a type with unexported properties, obviously. Kinda like in C++ for classes not providing copy constructor, but in Go Pimpl feels a lot less awkward, befitting the goroutines' share by communicating philosophy.

Solution 5

Your concern seems to be more about allocation than immutability. Immutability certainly impacts allocation by making it impossible to reuse memory. A clever compiler could conceivably reuse any "immutable" memory whose address it knows doesn't escape.

Aside from strings, be careful with interfaces. Anything larger than word size will have to be allocated when assigned to the interface (optimizations aside). Also, variables declared in a loop body whose addresses escape, including via a closure, will have to be allocated each time through the loop. Otherwise, though, an assignment is just an assignment. The value just gets copied into the memory represented by the variable.

If you use make or new in a loop, or any literal that produces a reference, allocation will have to happen (again, subject to optimization).

Basically, it all boils down to trying to reuse memory where you can, and hoping the compiler does it for you when you can't, if it makes any sense to do so.

Share:
26,966
Kristen
Author by

Kristen

philhk.com

Updated on July 09, 2022

Comments

  • Kristen
    Kristen almost 2 years

    In Google Go, I read that Strings are immutable, ok but are int's? What about other types? As a slightly older programmer I prefer mutability even though I know the benefits of immutability, I prefer to live dangerously.

    Know what types are mutable or immutable would be very helpful.


    Update, what I am mostly concerned about is the practical issues depending upon the type being mutable or immutable. As in the typical example in Java, if you create a String in a loop and loop for 10,000 times, you will get 10,000 String's created which are then later garbage collected. This has actually been a serious issue in a project in a company I worked at.

    The the question is, does Go's Immutability in some cases cause the same problem?

    It affects how you should treat the var. (or I assume it does).


    Update again, I am also concerned about other practical concerns. Knowing that something is immutable means that I can write code which is parallel and updates to one reference of the object should not update the other references. However sometimes I wish to do dangerous things, I want mutability.

    These are consequences of mutability vs immutability and affect how I can write the code.

    • Kristen
      Kristen over 12 years
      The reason that I ask is that this is a performance issue, if I am writing a loop which goes around a million times, I don't want lots of objects created. For example in a Java loop, we don't want to create a string on every time we go around the loop, so we use StringBuffer.
    • Kristen
      Kristen over 12 years
      My assumption is of course that immutable types are going to create lots of objects in general. (may not be true, depending upon the allocator)
    • ypb
      ypb over 12 years
      right, in a way, because extremely smart garbage collector could possibly reuse string fragments you leave behind with some clever (anything aside from contiguous array of words) implementation. use []byte then, caveat being that in full blown utf-8 character (aka rune) has variable length.
  • Kristen
    Kristen over 12 years
    Yes but if I have an int, and I set its value, and I creating a new instance of the int (immutable) or setting its value in memory (overwrite, mutable). Alternatively, am I somehow protected from even knowing if that is the case and it is up to the implementation of Go? hmm maybe I can think of some how to test this, not sure.
  • Kristen
    Kristen over 12 years
    package main import "fmt" func main() { var i int i = 5 fmt.Println(&i) i = 6 fmt.Println(&i) var k = 7 i = k fmt.Println(&i) }
  • ypb
    ypb over 12 years
    @Phil not sure what to tell you. perhaps only that Go is pass by value, so you have to explicitly take address of an object and the only "referency" type is untyped interface{}. /hmmm... not much of a teacher, moi ;}
  • SteveMcQwark
    SteveMcQwark over 12 years
    @Phil 1 - The integer is a value. This means that the variable is the instance. It represents the actual memory location where the int is stored, not a reference to it. So assigning to the variable can't create a new instance. To prove this, notice that the address of a variable doesn't change after it has been assigned to.
  • Admin
    Admin over 12 years
    About your sentence "The test for whether something is mutable is if you give that thing to someone, can you change some aspect of it ...": I think what you wrote is a valid viewpoint. But it seems to me that it is better (from my viewpoint) to think about mutability in terms of naming and composition/overlapping. That is, how to get the "name" of an object, change the object, and which other named objects are changed as a consequence of that. A "name" is a conceptual thing here.
  • newacct
    newacct over 12 years
    okay I deleted that section since I realize that's actually about reference types
  • eonil
    eonil over 10 years
    struct is definitely mutable type, but we don't feel it because it's always being copied when passing. So mutation doesn't get propagated.
  • Craig Jones
    Craig Jones over 9 years
    Thank you! This was exactly the information I needed to debug a problem with a missing asterisk in a method signature. It's surprising to me that Go will let you shoot yourself in the foot so easily in this regard, when it's so obnoxiously vocal about "helping" you in other ways.
  • hmijail
    hmijail over 3 years
    @robothor thank you for spelling the difference between the receiver being T and *T; that just allowed me to finish a day-long bug hunt. How did you find about that? I'm hoping I'm missing some good language reference, because I've just retraced the Go spec and Effective Go and... yeah, this info is there, but only if you know exactly what to look for!
  • user7860670
    user7860670 over 2 years
    This answer is misleading because pointers are mutable.