Tuples in Swift, Advanced Usage and Best Practices

Tuples for Pattern Matching

Tuples for Pattern Matching

Pattern matching oftentimes feels like the strongest use case for tuples. Swift's switch statement offers a really powerful yet easy way to define complex conditionals without cluttering up the source code. You can then match for the type, existence, and value of multiple variables in one statement.

We wrote a game where both players have to take a quiz. After each question we evaluate who won or lost. There're four states:

  • Player 1 is correct
  • Player 2 is correct
  • Both were correct
  • Both were wrong

We can model this logic very nicely with a switch statement such as the following:

let player1 = true
let player2 = false
switch (player1, player2) {
case (true, false): print("Player 1 won")
case (false, true): print("Player 2 won")
case (true, true): print("Draw, both won")
case (false, false): print("Draw, both lost")
}

Here, we create a tuple (player1, player2) and then match each of the possible cases.

Much more complex matchings are also possible. Below, we will match over a tuple that has the type (Int, String?, Any).

// Contrived example
// These would be return values from various functions.
let age: Int = 23
let job: String? = "Operator"
let payload: Any = ["cars": 1]

In the code above, we want to find the persons younger than 30 with a job and a Dictionary payload. Imagine the payload as something from the Objective-C world, it could be a Dictionary or an Array or a Number, weakly typed code that somebody else wrote years ago, and you have to interact with it now.

switch (age, job, payload) {
case (let age, _?, _ as Dictionary<AnyHashable, Any>) where age < 30:
    print(age)
default:
    break
}

By constructing the switch argument as a tuple (age, job, payload) we can query for specific or nonspecific attributes of all tuple elements at once. This allows for elaborately constrained conditionals.