Tuples
Reviewed & published by Brayan K
Tuples bundle a handful of values into one. By the end of this lesson you'll group values, name and decompose their elements, and return multiple values from a function — Swift's lightweight alternative to a one-off struct.
Part of the free Swift course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
- • Group several values into one tuple, e.g. (Int, String)
- • Access elements by position (.0, .1) and by name
- • Decompose a tuple into separate constants
- • Ignore elements you don't need with _
- • Return multiple values from a function via a tuple
1️⃣ Grouping Values
A tuple combines several values — possibly of different types — into one. Access elements by position with .0, .1, and so on (zero-based).
// A TUPLE groups several values into one compound value.
// The values can be different types.
let person = ("Ada", 36) // (String, Int)
// Access by POSITION with .0, .1, ... (zero-based).
print(person.0) // Ada
print(person.1) // 36
// You can annotate the type explicitly:
let coord: (Double, Double) = (1.5, 2.0)
print(coord.0, coord.1) // 1.5 2.02️⃣ Named Elements
Give elements names for readability — (x: 3, y: 5) — then read them by label like point.x. Positional access still works too.
// NAME the elements for readability — then access them by label.
let point = (x: 3, y: 5)
print(point.x) // 3
print(point.y) // 5
// Named tuples still support positional access too.
print(point.0) // 3
// Mixed types are fine and common:
let httpStatus = (code: 404, message: "Not Found")
print("\(httpStatus.code): \(httpStatus.message)") // 404: Not Found3️⃣ Decomposition
Unpack a tuple's elements into separate constants in one statement. Use _ to skip parts you don't need. This pattern is everywhere in Swift loops over pairs.
// DECOMPOSE a tuple into separate constants in one line.
let http = (200, "OK")
let (code, message) = http
print("Code \(code), message \(message)") // Code 200, message OK
// Use _ to ignore parts you don't need.
let point = (x: 10, y: 20)
let (justX, _) = point
print("x is \(justX)") // x is 10
// Decomposition shines in loops over (key, value) pairs:
for (name, score) in [("Ann", 9), ("Ben", 7)] {
print("\(name) scored \(score)")
}4️⃣ Returning Multiple Values
A function can return a tuple to hand back several related results at once — no extra type required. The caller reads them by label or decomposes them.
// Tuples let a function return MULTIPLE values at once.
func minMax(_ numbers: [Int]) -> (min: Int, max: Int) {
var lo = numbers[0]
var hi = numbers[0]
for n in numbers {
if n < lo { lo = n }
if n > hi { hi = n }
}
return (lo, hi) // return a tuple
}
let result = minMax([3, 8, 1, 6])
print("min = \(result.min)") // min = 1 (access by label)
print("max = \(result.max)") // max = 8
// Or decompose the returned tuple directly:
let (lowest, highest) = minMax([5, 2, 9])
print("\(lowest)..\(highest)") // 2..9Your turn. Fill in the blanks, then run it and check the output.
// 🎯 YOUR TURN — replace each ___ then run it in SwiftFiddle.
// 1) Make a NAMED tuple describing a book: title (String) and pages (Int).
let book = (title: "Swift", pages: ___) // 👉 e.g. 320
// 2) Print the title using its label.
print(book.___) // 👉 replace ___ with title
// 3) DECOMPOSE the tuple into two constants, ignoring the title with _.
let (_, count) = ___ // 👉 replace ___ with book
print("Pages: \(count)")
// ✅ Expected output (pages = 320):
// Swift
// Pages: 320Pro Tips
- 💡 Name the elements. (code: 200, message: "OK") reads far better than .0/.1.
- 💡 Decompose at the call site for clarity: let (min, max) = minMax(list).
- 💡 Use _ to ignore the parts you don't care about.
- 💡 Graduate to a struct once a tuple grows beyond a few fields or needs behaviour.
Common Errors (and the fix)
- Using t[0] instead of t.0 — tuples are indexed with dot-number, not subscripts.
- "Value of tuple type has no member 'x'" — you accessed a label the tuple doesn't define. Name the element when you create it.
- Decomposition arity mismatch — let (a, b) = (1, 2, 3) fails; the number of names must match the elements.
- Overusing tuples — large, persisted, or behaviour-bearing data belongs in a struct, not a sprawling tuple.
📋 Quick Reference
| Task | Code | Result |
|---|---|---|
| Create | let t = ("Ada", 36) | (String, Int) |
| By position | t.0 | first element |
| Named | (x: 3, y: 5).x | 3 |
| Decompose | let (a, b) = t | a, b separately |
| Ignore | let (_, b) = t | skip first |
| Return many | -> (min: Int, max: Int) | two values |
Mini-Challenge: Divide with Remainder
Build it, run it, and check your output against the example in the comments.
// 🎯 MINI-CHALLENGE: Divide with remainder
// 1. Write a function divide(_ a: Int, by b: Int) -> (quotient: Int, remainder: Int)
// that returns (a / b, a % b) as a NAMED tuple.
// 2. Call it with divide(17, by: 5) and store the result.
// 3. Print "17 / 5 = 3 remainder 2" using the .quotient and .remainder labels.
// 4. Then decompose a second call let (q, r) = divide(20, by: 6) and print q and r.
//
// ✅ Example output:
// 17 / 5 = 3 remainder 2
// 20 / 6 = 3 r 2
// your code here🎉 Lesson Complete!
- ✅ Tuples group several values (possibly different types) into one
- ✅ Access by position (.0) or by name (point.x)
- ✅ Decompose with let (a, b) = t; skip parts with _
- ✅ Return multiple values from a function via a tuple
Practice quiz
What is a tuple in Swift?
- An array of one type
- A key-value map
- A group of multiple values combined into one compound value
- A kind of optional
Answer: A group of multiple values combined into one compound value. A tuple groups several values, which can be of different types, into one value.
Can the elements of a tuple have different types?
- Yes, e.g. (Int, String)
- No, they must match
- Only two same-type values
- Only with classes
Answer: Yes, e.g. (Int, String). Tuple members may each have a different type.
How do you access the first element of an unnamed tuple `t`?
- t[0]
- t.first
- t(0)
- t.0
Answer: t.0. Unnamed tuple members are accessed by position with .0, .1, etc.
Given let point = (x: 3, y: 5), how do you read the x value?
- point.0 only
- point.x
- point["x"]
- point->x
Answer: point.x. Named tuple elements are accessed by their label, e.g. point.x.
What does `let (a, b) = (1, 2)` do?
- Decomposes the tuple, binding a=1 and b=2
- Creates a dictionary
- Raises an error
- Creates an array
Answer: Decomposes the tuple, binding a=1 and b=2. This is tuple decomposition: each element is bound to a name.
What is a common use of tuples?
- Storing thousands of items
- Replacing classes
- Returning multiple values from a function
- Looping forever
Answer: Returning multiple values from a function. Tuples let a function return several related values at once.
If a function returns (min: Int, max: Int), how do you read the max?
- result.maximum
- result.1 or result.max
- result[1].max
- result->max
Answer: result.1 or result.max. You can use the label result.max or the position result.1.
What is the index of the second element of an unnamed tuple?
- .2
- [1]
- .second
- .1
Answer: .1. Positions are zero-based, so the second element is .1.
Can you ignore a tuple element during decomposition?
- No
- Yes, using an underscore _ in its place
- Only the first one
- Only named ones
Answer: Yes, using an underscore _ in its place. Use _ to ignore an element you don't need, e.g. let (_, y) = point.
Are tuples best for large, long-lived data models?
- Yes, always prefer them
- Yes, they replace structs
- No — for richer/persisted data, prefer a struct
- Only for networking
Answer: No — for richer/persisted data, prefer a struct. Tuples are great for lightweight grouping; structs are better for substantial models.
Continue this course
- Previous: Dictionaries & Sets
- Next: Enumerations & Associated Values — Model a fixed set of cases — raw values, associated values, and switch
Frequently asked questions
What is a tuple and when should I use one?
A tuple groups several values — possibly of different types — into one compound value, like (Int, String). They're perfect for lightweight, temporary grouping: returning two related values from a function, pairing a key with a value in a loop, or bundling coordinates. For richer, longer-lived data with behaviour, prefer a struct.
How do I access tuple elements?
By position using dot-number syntax: tuple.0, tuple.1, and so on (zero-based). If you give the elements names when you create the tuple — for example (x: 3, y: 5) — you can access them by label too: point.x. Named tuples are far more readable and still support positional access.
What is tuple decomposition?
Decomposition unpacks a tuple's elements into separate named constants or variables in one statement: let (code, message) = (200, "OK") binds code to 200 and message to "OK". You can ignore parts you don't need with an underscore, e.g. let (_, message) = response. It reads cleanly and avoids repeated .0/.1 access.
How does a function return multiple values?
Make its return type a tuple. For example -> (min: Int, max: Int) returns two named integers. The caller can read them by label (result.min) or decompose the result directly with let (lo, hi) = result. This is the idiomatic Swift way to hand back several related results without defining a whole new type.
Should I use a tuple or a struct?
Use a tuple for small, throwaway groupings that live briefly and have no behaviour. Reach for a struct when the data is meaningful across your program, needs methods, conforms to protocols, or will be stored and passed around widely — a named type with documented properties is clearer and more maintainable than a sprawling tuple.