# Swift In-Out Parameters (inout): Syntax, Examples, and Rules

Source: https://devdocs10.com/articles/swift/swift-inout-parameters  
By Murat Bo · Published 2026-05-16 · DevDocs10 (https://devdocs10.com)

Swift `inout` parameters let a function temporarily modify a value that was passed in by the caller. This is useful when a function needs to change an existing variable directly instead of returning a new value. In this article, you will learn how `inout` works, when to use it, how to call functions with `&`, and which errors and edge cases often confuse beginners.

> **Quick answer:** In Swift, mark a function parameter with `inout` when the function should change the caller's variable. When calling that function, you must pass a variable with `&`, because constants, literals, and temporary values cannot be used as `inout` arguments.

> **Difficulty:** Beginner
>
> **Helpful to know first:** You'll understand this better if you already know basic Swift function syntax, variables declared with `let` and `var`, and how functions can return values.

## 1. What Is In-Out Parameters (inout)?

An `inout` parameter is a function parameter that allows the function to modify the original value supplied by the caller.

Normally, Swift function parameters are constants inside the function. That means you can read them, but you cannot assign a new value to them. The `inout` keyword changes that behavior for a specific parameter.

- `inout` is written before the parameter's type.
- The caller passes a variable using the `&` prefix.
- The function can change that variable's value.
- You can use `inout` only with variables, not constants or literals.
- It is often used for swapping, accumulating, normalizing, or updating multiple values in one call.

> Although people sometimes describe `inout` as "pass by reference," Swift actually uses a copy-in, copy-out model with compiler optimizations. For everyday use, the practical idea is simple: the function can update the caller's variable.

## 2. Why In-Out Parameters (inout) Matters

`inout` matters because some tasks are easier to express when a function directly updates an existing variable.

Without `inout`, you often need to return a new value and then assign it back yourself. That is usually fine, and sometimes better, but there are cases where changing the original variable is clearer.

Real situations where `inout` helps include:

- Swapping two values.
- Incrementing counters or totals.
- Clamping a number into a valid range.
- Updating multiple values in a single function call.
- Writing utility functions that adjust state in place.

At the same time, `inout` should not be overused. If a function only needs to calculate and return a result, a normal return value is often simpler and easier to read.

## 3. Basic Syntax

The basic syntax has two parts:

- In the function definition, mark the parameter as `inout`.
- In the function call, pass a variable using `&`.

### Declaring an inout parameter

Here is the smallest useful example. The function increases a number by one.

```swift
func increment(value: inout Int) {
    value += 1
}

var count = 5
increment(value: &count)
print(count) // 6
```

Output (tested with Swift 6.4):

```text
6
```

The parameter `value` is marked as `inout`, so the function is allowed to modify it. In the call, `&count` tells Swift to pass the variable as an `inout` argument.

### What each part means

In the example above:

- `func increment(...)` defines a function.
- `value: inout Int` means the function can change an `Int` variable.
- `&count` means "pass this variable so the function can update it."

### Swift inout vs returning a value

This topic is commonly confused with simply returning a new value. Both approaches are valid, but they communicate different intent.

```swift
func incremented(value: Int) -> Int {
    return value + 1
}

var score = 10
score = incremented(value: score)
```

This version does not modify the argument directly. It returns a new value, and the caller decides what to do with it.

Use a return value when the function is producing a result. Use `inout` when the function's purpose is specifically to update an existing variable.

## 4. Step-by-Step Examples

### Example 1: Increase a player's score

This example shows a practical numeric update.

```swift
func addBonus(to score: inout Int, points: Int) {
    score += points
}

var playerScore = 120
addBonus(to: &playerScore, points: 30)
print(playerScore) // 150
```

Output (tested with Swift 6.4):

```text
150
```

The function updates the original score variable directly. This is useful when your intent is clearly "change this stored value."

### Example 2: Swap two values

One classic use of `inout` is swapping values.

```swift
func swapNumbers(_ a: inout Int, _ b: inout Int) {
    let temporary = a
    a = b
    b = temporary
}

var left = 3
var right = 9

swapNumbers(&left, &right)
print(left, right) // 9 3
```

Output (tested with Swift 6.4):

```text
9 3
```

After the function call, the values have exchanged places because both caller variables were passed as `inout` arguments.

### Example 3: Clamp a number into a valid range

This pattern is useful when user input or calculations may produce invalid values.

```swift
func clamp(_ value: inout Int, min: Int, max: Int) {
    if value < min {
        value = min
    } else if value > max {
        value = max
    }
}

var volume = 130
clamp(&volume, min: 0, max: 100)
print(volume) // 100
```

Output (tested with Swift 6.4):

```text
100
```

The function directly corrects the existing value, which can be clearer than returning a replacement when the goal is validation or normalization.

### Example 4: Update two related values together

`inout` becomes especially useful when a function needs to change more than one variable.

```swift
func applyPurchase(price: Int, balance: inout Int, itemsBought: inout Int) {
    balance -= price
    itemsBought += 1
}

var wallet = 200
var purchases = 0

applyPurchase(price: 45, balance: &wallet, itemsBought: &purchases)
print(wallet) // 155
print(purchases) // 1
```

Output (tested with Swift 6.4):

```text
155
1
```

This avoids returning a tuple just to write values back into existing variables.

## 5. Practical Use Cases

- Updating a game score, lives count, or timer directly.
- Normalizing user-entered numbers such as percentage, age, or quantity limits.
- Swapping two values in utility code or algorithm practice.
- Adjusting multiple pieces of state together, such as a balance and a transaction count.
- Writing helper functions that mutate a value in place for clearer intent.
- Working with custom types when a function should modify a caller-owned value instead of building a replacement.

## 6. Common Mistakes

### Mistake 1: Forgetting the & when calling the function

When a function expects an `inout` parameter, the caller must pass a variable with `&`. This is part of the syntax, not an optional extra.

**Problem:** This call passes a normal argument instead of an `inout` argument, so Swift reports that the parameter requires `&`.

```swift
func doubleValue(_ number: inout Int) {
    number *= 2
}

var points = 8
doubleValue(points)
```

**Fix:** Add `&` before the variable when calling the function.

```swift
func doubleValue(_ number: inout Int) {
    number *= 2
}

var points = 8
doubleValue(&points)
```

The corrected version works because the argument is now passed as an `inout` value.

### Mistake 2: Passing a constant or literal to an inout parameter

Only mutable variables can be passed to an `inout` parameter. Constants declared with `let` and literal values cannot be modified.

**Problem:** This code tries to pass values that cannot be changed, so Swift rejects them. You may see errors such as "Cannot pass immutable value as inout argument" or similar compiler messages.

```swift
func increase(_ value: inout Int) {
    value += 1
}

let fixedNumber = 10
increase(&fixedNumber)

increase(&10)
```

**Fix:** Store the value in a mutable variable declared with `var` before passing it.

```swift
func increase(_ value: inout Int) {
    value += 1
}

var number = 10
increase(&number)
```

The corrected version works because `number` is a mutable variable that the function is allowed to update.

### Mistake 3: Trying to modify a normal parameter directly

Swift function parameters are constants by default. If you need to assign a new value to a parameter inside the function, you must either use `inout` or copy the value into a local variable.

**Problem:** This function attempts to reassign a regular parameter, which Swift does not allow. A common compiler message is "Left side of mutating operator isn't mutable: 'value' is a 'let' constant."

```swift
func addTen(value: Int) {
    value += 10
}
```

**Fix:** If the caller's variable should change, use `inout`. Otherwise, create and return a new value.

```swift
func addTen(value: inout Int) {
    value += 10
}

var total = 5
addTen(value: &total)
```

The corrected version works because the parameter is explicitly declared as mutable input from the caller.

### Mistake 4: Passing the same variable to multiple inout parameters

Swift protects memory access carefully. If the same variable is passed to two `inout` parameters at the same time, the accesses overlap.

**Problem:** This creates conflicting read and write access to the same memory location. Swift may report an error such as "Overlapping accesses to 'value', but modification requires exclusive access."

```swift
func adjustBoth(_ a: inout Int, _ b: inout Int) {
    a += 1
    b += 1
}

var value = 10
adjustBoth(&value, &value)
```

**Fix:** Pass different variables, or redesign the function so it modifies one value at a time.

```swift
func adjustBoth(_ a: inout Int, _ b: inout Int) {
    a += 1
    b += 1
}

var first = 10
var second = 20
adjustBoth(&first, &second)
```

The corrected version works because each `inout` parameter now has exclusive access to a different variable.

## 7. Best Practices

### Use inout only when mutation is the main purpose

Some functions are clearer when they return a value instead of changing an argument. Choose `inout` when in-place modification is the point of the function.

```swift
// Less preferred when you only need a computed result
func square(_ value: inout Int) {
    value *= value
}

// Often clearer
func squared(_ value: Int) -> Int {
    return value * value
}
```

This keeps function intent clearer: one version changes a variable, and the other computes a result.

### Give inout parameters names that suggest change

Parameter labels can make mutating behavior easier to understand at the call site.

```swift
func reset(_ value: inout Int) {
    value = 0
}

func reset(score: inout Int) {
    score = 0
}
```

The second version reads more clearly because the label explains what is being changed.

### Keep inout functions focused and predictable

A function that changes too many unrelated values can be hard to reason about. Prefer small, clear mutations.

```swift
// Harder to reason about
func process(_ score: inout Int, _ name: inout String, _ isActive: inout Bool) {
    score += 10
    name = name.uppercased()
    isActive = true
}

// Clearer and more focused
func activate(_ flag: inout Bool) {
    flag = true
}
```

Small functions are easier to test, reuse, and understand.

## 8. Limitations and Edge Cases

- You must pass a mutable variable with `&`. Constants, literals, and expressions do not work.
- Swift enforces exclusive access to memory, so overlapping `inout` access can produce compile-time or runtime errors.
- `inout` does not mean unrestricted shared mutation. Swift still protects safety rules carefully.
- Using `inout` can make code less obvious if the function name does not clearly signal mutation.
- For many simple operations, returning a new value is easier to read than mutating in place.
- When working with computed properties or complex access patterns, Swift may reject certain `inout` uses because of exclusive access rules.

> If your code feels awkward with many `inout` parameters, that is often a sign the function should return a result, use a tuple, or be redesigned around a type that manages its own state.

## 9. Practical Mini Project

This mini project builds a small score manager using several `inout` helper functions. It shows how in-place updates can make state changes readable.

```swift
func addPoints(_ score: inout Int, points: Int) {
    score += points
}

func applyPenalty(_ score: inout Int, points: Int) {
    score -= points
}

func clampToZero(_ score: inout Int) {
    if score < 0 {
        score = 0
    }
}

var score = 50

addPoints(&score, points: 20)
applyPenalty(&score, points: 80)
clampToZero(&score)

print("Final score: \(score)") // Final score: 0
```

Output (tested with Swift 6.4):

```text
Final score: 0
```

This example uses three focused functions. Each one performs one clear mutation, and the final result is easy to trace. That is a good style for `inout`: simple functions with obvious effects.

## 10. Key Points

- `inout` lets a function modify the caller's variable.
- You declare `inout` in the parameter type and pass the argument with `&`.
- Only mutable variables declared with `var` can be passed as `inout` arguments.
- Normal function parameters are constants inside the function.
- `inout` is useful for direct updates, swaps, and coordinated state changes.
- Swift enforces exclusive memory access, so overlapping `inout` usage can fail.
- Sometimes returning a new value is clearer than mutating an argument.

## 11. Practice Exercise

Try this exercise to check your understanding of `inout`.

- Create a function named `applyDiscount`.
- The function should take an `inout Int` named `price`.
- It should also take an `Int` named `discount`.
- Subtract the discount from the price.
- If the result is less than 0, set the price to 0.
- Call the function with a variable price and print the final value.

**Expected output:** If the starting price is 40 and the discount is 50, the final printed value should be 0.

**Hint:** Remember to mark the parameter with `inout` and use `&` at the call site.

```swift
func applyDiscount(price: inout Int, discount: Int) {
    price -= discount

    if price < 0 {
        price = 0
    }
}

var itemPrice = 40
applyDiscount(price: &itemPrice, discount: 50)
print(itemPrice) // 0
```

Output (tested with Swift 6.4):

```text
0
```

## 12. Final Summary

Swift `inout` parameters give functions a controlled way to modify a caller's variable. You use `inout` in the function definition and `&` when calling the function. This is especially useful for tasks like swapping values, adjusting counters, clamping numbers, or updating multiple related variables in one operation.

The most important things to remember are that only mutable variables can be passed as `inout` arguments, normal parameters are constant by default, and Swift enforces exclusive access rules to keep memory safe. If a function is really just computing a result, returning a value may be the clearer choice.

As a next step, it helps to learn how `mutating` methods work on structs and how Swift handles value types, because those concepts connect closely to how and why `inout` behaves the way it does.
