SLN SLN -4 years ago 110
Swift Question

Mutable and Modifialbe what is the meaning of them?

Let's start with some code segments

struct DigitS {
var number = 42
init(_ n: Int) {
self.number = n
}
mutating func replace() {
self = DigitS(12) // mutating
}
}

class DigitC {
var number = 42
init(_ n: Int) {
self.number = n
}
func replace() {
self = DigitC(12) //#Cannot assign to value: "self" is immutable
}
}


For a very long time, I was very confused about the meaning of mutable, modifiable. Here are some of my understandings so far, would be nice if you can point out all errors it may have


  1. Mutating function in the structure type above does not "mutates" the instance, it will replace the old value of the variable by a totally new one

  2. Mutating means: the action like assignment, initialization or mutating function does not modifies the current value but a triggers a replacement

  3. A class typed variable's value is immutable, but you can modify/change the current value (this is the reason the compiler gives out the warning, please see the comments with #)

  4. The setter observer, can only be called if the type is a value type, because setter tells if the variable has been mutated/replaced (please see code below)

    struct Digit {
    var number = 12
    }
    var b = Digit() {
    didSet{ print("number is set") }
    }
    b.number = 22 // observer is called



    class Digit {
    var number = 12
    }
    var b = Digit() {
    didSet{ print("number is set") }
    }

    b.number = 22 // observer is not called



Thanks for your time and help

Answer Source

Dealing with memory tend be better explained using images, but I'll give it a go here:

  1. You're sort of right, it's actually changing the data stored at the location of the variable.

Given a simple struct with a mutator:

struct Example {
    var text: String

    mutating func changeText(to newText: String) {
        self.text = newText
    }
}

let constantExample = Example(text: "Test") //Makes a section of memory that isn't allowed to change.
constantExample.changeText(to: "Other Test") //This doesn't work because constantExample isn't mutable.

var mutableExample = Example(text: "Test") //Makes a section of memory that is allowed to change.
mutableExample.changeText(to: "Other Test") //This doesn't make a new copy, but rather changes the value in mutableExample's section of memory

If you were to use the specific case you mentioned:

mutating func changeText(to newText: String) {
    self = Example(text: "A new text")
}

mutableExample will still reside in the same memory location, but you are manually Creating a completely new instance of the Example and then copying that data from that instance to mutableExample.

  1. The opposite :) Mutating changes the instance in-place. You can change that instance by copying a different value, (as happens in the self = example), but the instance is still the same instance, just with a different value.

  2. When creating a class variable, you are creating a reference to a section of memory. When setting or changing that reference var variableName = classInstance the location of reference remains the same once initialized, but the location being referenced (if a var) can then change.

  3. You're functionally correct, but missing some nuance. In the struct example, as previously stated the actual value of the instance is changing. In the class example, the referenced memory is changing, but the actual value stored within b does not change.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download