Swift
programming
underscore
references
syntax

What's the _ underscore representative of in Swift References?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If you have spent any time reading Swift code, you have almost certainly encountered the underscore character _ appearing in unexpected places. Unlike most languages where _ is simply a valid identifier character, Swift gives it special meaning in several distinct contexts. Understanding these uses is essential for reading Swift APIs, writing idiomatic functions, and working with pattern matching effectively.

Omitting External Parameter Labels

By default, every Swift function parameter has both an external label (used at the call site) and an internal name (used inside the function body). Placing _ as the external label tells the compiler that callers should not provide a label for that argument.

swift
1// Without underscore: caller must write greet(person: "Alice")
2func greet(person name: String) {
3    print("Hello, \(name)!")
4}
5greet(person: "Alice")
6
7// With underscore: caller writes greet("Alice")
8func greet(_ name: String) {
9    print("Hello, \(name)!")
10}
11greet("Alice")

This is extremely common in the Swift standard library and Apple frameworks. For example, print(_:) uses an underscore so you write print("Hello") instead of print(items: "Hello"). You will also see it on the first parameter of many UIKit methods where the label would be redundant with the function name, like tableView(_:numberOfRowsInSection:).

Discarding Return Values

When a function returns a value that you intentionally do not need, Swift normally produces a compiler warning. You can silence that warning by assigning the result to _.

swift
1@discardableResult
2func saveToDatabase() -> Bool {
3    // ... save logic ...
4    return true
5}
6
7// Without underscore: warning about unused result
8saveToDatabase()
9
10// With underscore: explicitly discarding the result
11_ = saveToDatabase()

This communicates to both the compiler and other developers that you deliberately chose not to use the return value.

Ignoring Tuple Elements

When destructuring a tuple, you can use _ to skip elements you do not care about.

swift
1func getUser() -> (String, Int, String) {
2    return ("Alice", 30, "[email protected]")
3}
4
5// Only care about the name and email
6let (name, _, email) = getUser()
7print("\(name): \(email)")  // "Alice: [email protected]"

You can use _ for as many elements as you like. If you only need the age, write let (_, age, _) = getUser().

Ignoring Loop Variables

In a for loop where you only need to repeat an action a certain number of times without using the loop index, _ replaces the loop variable.

swift
1// Print "Hello" 5 times without needing the index
2for _ in 1...5 {
3    print("Hello")
4}

This is a clear signal that the iteration count matters but the current index does not.

Pattern Matching in switch Statements

In switch statements and if case expressions, _ acts as a wildcard pattern that matches any value.

swift
1let point = (2, 0)
2
3switch point {
4case (0, 0):
5    print("At the origin")
6case (_, 0):
7    print("On the x-axis")  // matches any x, y must be 0
8case (0, _):
9    print("On the y-axis")
10case (_, _):
11    print("Somewhere else")
12}

This is especially useful with enums that have associated values when you want to match the case but ignore the payload.

swift
1enum NetworkResult {
2    case success(Data)
3    case failure(Error)
4}
5
6let result: NetworkResult = .success(Data())
7
8switch result {
9case .success(_):
10    print("Request succeeded")
11case .failure(_):
12    print("Request failed")
13}

Numeric Literals Readability

Swift allows _ as a visual separator inside numeric literals to make large numbers easier to read. This is purely cosmetic and has no effect on the value.

swift
let population = 7_900_000_000   // 7.9 billion
let hexColor = 0xFF_AA_33
let binary = 0b1010_1100_0011

Ignoring Closure Parameters

When a closure receives parameters you do not need, replace them with _.

swift
1let numbers = [1, 2, 3, 4, 5]
2
3// enumerated() gives (index, element), but we only want the index
4let indices = numbers.enumerated().map { (index, _) in
5    return index * 2
6}
7print(indices)  // [0, 2, 4, 6, 8]

Common Pitfalls

  • Overusing _ for external labels: Removing all parameter labels can make call sites ambiguous. Use _ only when the function name already makes the argument's role obvious.
  • Accidentally discarding important return values: Assigning to _ suppresses warnings, but if the return value indicates an error condition, you may be silently ignoring failures.
  • Confusing _ in patterns with default: In a switch statement, case _: and default: both match everything, but default must be the last case. Prefer default for catch-all branches.
  • Using _ as an actual variable name: While _ is technically assignable, you cannot read from it. Writing let _ = value and then trying to use _ later will not compile.
  • Forgetting _ in delegate methods: Many Cocoa delegate methods require _ as the external label for their first parameter. Omitting it changes the method signature and the method will not be called.

Summary

  • _ as an external parameter label lets callers omit the argument label at the call site.
  • _ = expression explicitly discards a return value and silences compiler warnings.
  • _ in tuple destructuring, for loops, and closure parameters ignores values you do not need.
  • _ in switch cases acts as a wildcard pattern matching any value.
  • _ inside numeric literals serves as a visual separator for readability.

Course illustration
Course illustration

All Rights Reserved.