Menu
Coddy logo textTech

Mutating Methods

Part of the Object Oriented Programming section of Coddy's Swift journey. Lesson 9 of 57.

A struct method that changes a property must be marked mutating. Without the keyword the method does not compile, because methods of a value type treat self as constant:

struct Counter {
    var count = 0

    mutating func increment() {
        count += 1
    }
}

var c = Counter()
c.increment()
c.increment()
print(c.count)

Output:

2

A mutating method can only be called on a var. On a let constant the call does not compile, because the whole value is fixed:

var a = Counter()
a.increment()        // fine

let b = Counter()
// b.increment()     // error: b is a let constant

Methods that only read properties stay non-mutating and work on constants too. A good design keeps changes in a few mutating methods:

struct Stack {
    var items: [Int] = []

    mutating func push(_ x: Int) { items.append(x) }
    mutating func pop() -> Int? { items.popLast() }
    func peek() -> Int? { items.last }
}

var s = Stack()
s.push(3)
s.push(8)
print(s.pop() ?? -1)
print(s.peek() ?? -1)

Output:

8
3

A mutating method can replace self entirely, which is handy for resetting a value:

struct Score {
    var points = 0
    var bonus = 0

    mutating func reset() {
        self = Score()
    }
}

var s = Score(points: 10, bonus: 3)
s.reset()
print(s.points + s.bonus)

Output:

0
challenge icon

Challenge

Easy

Complete the struct Wallet. add(_:) and spend(_:) are mutating: spend subtracts only when enough money is left and returns whether it did. report() is not mutating and returns balance 40.

The supplied code reads commands +n and -n, applies them to one var wallet, prints denied for a refused spending, and finally prints report().

Your code goes in Wallet.swift. main.swift holds the supplied input/output code and cannot be edited.

Try it yourself

// Supplied input/output code: keep it as it is
var input: [String] = []
while let line = readLine() { input.append(line) }
var wallet = Wallet()
for cmd in input {
    let amount = Int(cmd.dropFirst())!
    if cmd.hasPrefix("+") {
        wallet.add(amount)
    } else if !wallet.spend(amount) {
        print("denied")
    }
}
print(wallet.report())
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming

Practice on your own: Swift playground