Swift Bite — Mutating Functions
Value types such as Structs and Enums can have methods in Swift. These methods may want to modify the properties defined in the types. Consider an example of a struct Stack
that has an array property named items
and a function push(item:)
struct Stack {
private var items = [Int]()
func push(item: Int) {
// Error - Cannot use mutating member
// on immutable value: 'self' is immutable
items.append(item)
}
}
var stack = Stack()
stack.push(item: 10)
Here, the push(item:)
function attempts to add the item to the items
array. This will throw a compile-time error as we are trying to change the instance property, items,
from within the struct. It is not possible to change the properties inherently because, by default, the self
is declared as a let
for the value types.
Let’s understand this further. self
is inherently passed as a function parameter to every instance method of the type. As self
is declared as let
by default, there is no way we can mutate the instance (self
) or any properties on that instance from within the function.
As an alternative approach, we can very well create a new instance of the Stack
, copy the existing items
array and add the new item to the items
array.
struct Stack {
var items: [Int] = Array()
func push(item: Int) -> Stack {
var copy = items
copy.append(item)
return Stack(items: copy)
}
}
let stack = Stack()
let newStack = stack.push(item: 10)
This ends up creating a new copy of the struct every time we try to push a new item in the Stack
.
mutating Keyword
Swift provides a better way to mutate the value type and its properties inherently. Mark a function as mutating.
This makes self
passed as an inout
parameter to the function and lets us change its or its property’s value provided the properties are declared as a var
. Here is the code —
struct Stack {
private var items: [Int] = Array()
mutating func push(item: Int) {
// Works fine! self is passed as
// an inout variable here
self.items.append(item)
}
}
var stack = Stack()
stack.push(item: 10)
A function defined in the value type must be marked as
mutating
if the instance or the properties of the value type need to be mutated.