# Swift @discardableResult: Ignore Function Return Values Safely

Source: https://devdocs10.com/articles/swift/swift-discardable-result  
By Murat Bo · Published 2026-05-18 · DevDocs10 (https://devdocs10.com)

`@discardableResult` is a Swift function attribute that tells the compiler it is acceptable to call a function and ignore the value it returns. This matters because Swift normally warns you when a function returns something useful and you do not use it. Understanding this attribute helps you design clearer APIs and avoid warnings for functions that are sometimes used for their result and sometimes called only for their side effects.

> **Quick answer:** Use `@discardableResult` before a function or method declaration when callers may legitimately ignore its return value. It does not change what the function returns; it only suppresses the compiler warning about an unused result.

> **Difficulty:** Beginner
>
> **Helpful to know first:** You'll understand this better if you know basic Swift syntax, how functions return values, and why the compiler shows warnings for suspicious code.

## 1. What Is @discardableResult?

`@discardableResult` is an attribute you place on a function, method, or subscript declaration. It tells Swift that callers are allowed to ignore the returned value without receiving the usual unused-result warning.

- It is written directly above the function or method declaration.
- It does not remove the return value.
- It does not change the function's runtime behavior.
- It only affects compiler warnings about ignored results.
- It is most useful for APIs that both perform an action and return a helpful value.

Without this attribute, Swift often warns when returned values are ignored because that can indicate a bug. For example, if a function computes something important and the caller throws the result away, the compiler wants your attention. But some functions return a value only as a convenience, not as a requirement. That is where `@discardableResult` is useful.

> A common comparison is `@discardableResult` versus returning `Void`. Returning `Void` means there is no result to use. Using `@discardableResult` means there *is* a result, but callers are not forced to keep it.

## 2. Why @discardableResult Matters

Swift warnings are designed to catch mistakes early. If a function returns a value, ignoring it may mean you forgot to assign it, print it, or pass it along. That warning is often helpful.

However, some APIs are intentionally flexible:

- A logging function may return the message string for chaining or testing, but many callers just want the log side effect.
- A mutating method may return `self` to allow chaining, but some callers only care that the mutation happened.
- A configuration helper may return a status value, while many call sites simply trigger the operation.

In those cases, forcing every caller to use `_ = ...` just to silence warnings makes code noisy. `@discardableResult` lets the API express intent more clearly.

You should **not** use it just to hide a poor API design. If the return value is important for correctness, callers should see a warning when they ignore it.

## 3. Basic Syntax

### Declaring a function with @discardableResult

The attribute goes on the line above the declaration.

```swift
@discardableResult
func save(name: String) -> Bool {
    print("Saved \(name)")
    return true
}
```

This function still returns a `Bool`. The attribute simply says that ignoring that `Bool` is acceptable.

### Calling it and ignoring the result

Because the function is marked with `@discardableResult`, this call is allowed without an unused-result warning.

```swift
save(name: "Report.txt")
```

Output (tested with Swift 6.4):

```text
Saved Report.txt
```

The side effect happens, and the returned success value is discarded.

### Calling it and using the result

You can still use the returned value normally.

```swift
let didSave = save(name: "Notes.txt")
print("Success: \(didSave)")
```

Output (tested with Swift 6.4):

```text
Saved Notes.txt
Success: true
```

This is the key idea: the return value remains available, but using it is optional.

## 4. Step-by-Step Examples

### Example 1: A function that logs and returns a message

This example shows a function with a useful side effect and a useful result. Some callers may care about the returned string, while others may not.

```swift
@discardableResult
func logMessage(_ message: String) -> String {
    print("LOG: \(message)")
    return message
}

logMessage("App started")

let savedMessage = logMessage("User signed in")
print(savedMessage)
```

Output (tested with Swift 6.4):

```text
LOG: App started
LOG: User signed in
User signed in
```

The first call ignores the return value. The second call stores it. Both are valid because the function explicitly allows discarded results.

### Example 2: A mutating method that returns self for chaining

Builder-style APIs often return the modified instance so calls can be chained. But callers may also want to call the method only for its effect.

```swift
struct Counter {
    var value = 0

    @discardableResult
    mutating func increment() -> Int {
        value += 1
        return value
    }
}

var counter = Counter()
counter.increment()

let newValue = counter.increment()
print(newValue)
```

Output (tested with Swift 6.4):

```text
2
```

The method updates the counter either way. Returning the new value is a convenience, not a requirement.

### Example 3: Comparing with a normal function that returns a value

Now compare that behavior with a function that does *not* use `@discardableResult`. Ignoring the result is more suspicious here.

```swift
func square(_ number: Int) -> Int {
    return number * number
}

let result = square(4)
print(result)
```

Output (tested with Swift 6.4):

```text
16
```

This kind of function exists mainly to compute and return a value. If a caller ignores that value, the warning is useful, so adding `@discardableResult` would usually be the wrong choice.

### Example 4: A method that returns self

Returning `self` is common when you want optional chaining-like fluency in your own API design.

```swift
struct TextBuilder {
    var text = ""

    @discardableResult
    mutating func append(_ value: String) -> TextBuilder {
        text += value
        return self
    }
}

var builder = TextBuilder()
builder.append("Hello")
builder.append(", world")
print(builder.text)
```

Output (tested with Swift 6.4):

```text
Hello, world
```

Here the returned builder is optional to use. The real purpose may simply be updating the stored text.

## 5. Practical Use Cases

- Logging helpers that print or record information but also return the logged value for inspection.
- Builder-style APIs that return `self` so callers can chain calls if they want.
- Mutating methods that return the updated value as a convenience.
- Utility methods that perform a side effect first and expose a result second.
- Debug helpers used in development, where returning a value is nice but not essential.
- Internal APIs where some call sites need the result and others only need the action.

If the returned value is central to the function's purpose, do not use this attribute just to reduce warnings.

## 6. Common Mistakes

### Mistake 1: Adding @discardableResult to a pure calculation function

Some developers add `@discardableResult` everywhere to make warnings disappear. That hides useful feedback from the compiler.

**Problem:** This function exists to calculate and return a value. Ignoring that result is probably a bug, so suppressing the warning weakens the API.

```swift
@discardableResult
func multiply(_ a: Int, _ b: Int) -> Int {
    return a * b
}

multiply(3, 4)
```

**Fix:** Remove the attribute when the return value is the main point of the function.

```swift
func multiply(_ a: Int, _ b: Int) -> Int {
    return a * b
}

let product = multiply(3, 4)
print(product)
```

Output (tested with Swift 6.4):

```text
12
```

The corrected version preserves the compiler's warning behavior and makes the intended usage clear.

### Mistake 2: Thinking the attribute changes the return type

`@discardableResult` does not convert a function into a `Void`-returning function. The value is still returned and can still be captured.

**Problem:** This code assumes the method no longer returns anything, which can lead to API confusion and incorrect documentation.

```swift
struct ScoreTracker {
    var score = 0

    @discardableResult
    mutating func add(_ points: Int) -> Int {
        score += points
        return score
    }
}
```

**Fix:** Treat the attribute as permission to ignore the result, not as removal of the result.

```swift
var tracker = ScoreTracker()
tracker.add(10) // allowed to ignore

let currentScore = tracker.add(5)
print(currentScore)
```

Output (tested with Swift 6.4):

```text
15
```

The corrected version shows that the method still returns an `Int`; ignoring it is simply optional.

### Mistake 3: Using @discardableResult to hide an API design problem

Sometimes a function returns a value because the design is trying to serve too many purposes at once. Adding the attribute may hide that confusion instead of solving it.

**Problem:** This function both updates data and returns a status string, but the return value may not be meaningful enough to justify returning it at all.

```swift
@discardableResult
func updateSettings() -> String {
    print("Settings updated")
    return "Done"
}
```

**Fix:** If callers rarely need the result, consider returning `Void` instead of using `@discardableResult`.

```swift
func updateSettings() {
    print("Settings updated")
}
```

The corrected version is clearer because the function now communicates that the side effect is its real purpose.

## 7. Best Practices

### Use it only when ignoring the result is genuinely valid

If both of these usages make sense, the attribute is a good fit: using the result or ignoring it.

```swift
@discardableResult
func cache(_ value: String) -> Bool {
    print("Cached: \(value)")
    return true
}
```

This works well because storing the value is the main effect, while the success flag is a helpful extra.

### Prefer clear API design over warning suppression

If the result is not useful, returning `Void` is better than returning a throwaway value with `@discardableResult`.

```swift
// Less clear
@discardableResult
func startSession() -> String {
    return "Started"
}

// Preferred when the returned value adds little meaning
func startSession() {
    print("Session started")
}
```

The preferred version tells callers exactly what to expect and reduces unnecessary API complexity.

### Document why the return value can be ignored

This attribute is more useful when the reason is obvious from the function name, return type, and behavior.

```swift
struct DownloadTracker {
    var completed = 0

    @discardableResult
    mutating func markComplete() -> Int {
        completed += 1
        return completed
    }
}
```

Here the name suggests that the side effect is primary, while the returned count is a convenience.

## 8. Limitations and Edge Cases

- `@discardableResult` only affects warnings about unused return values. It does not change performance, logic, or memory behavior.
- It does not make an incorrect call correct. If a function must be used in a certain way for correctness, this attribute should not be added.
- It can make bugs harder to notice if overused, because ignored values no longer stand out.
- It is most appropriate for side-effect-first APIs, not result-first APIs.
- If a method returns `self` for chaining, the attribute is often reasonable because many callers will mutate without chaining.
- If you find yourself adding it to many unrelated functions, that may indicate an API design issue rather than a compiler-warning issue.

> If you only want to silence a warning at one call site, using `_ = someFunction()` can be clearer than changing the function declaration for every caller.

## 9. Practical Mini Project

This mini project creates a simple notes store. The `addNote` method updates stored data and returns the new count. Some callers use that count, while others simply add a note.

```swift
struct NotesStore {
    private(set) var notes: [String] = []

    @discardableResult
    mutating func addNote(_ text: String) -> Int {
        notes.append(text)
        return notes.count
    }

    func listNotes() {
        for note in notes {
            print("- \(note)")
        }
    }
}

var store = NotesStore()

store.addNote("Buy milk")

let totalNotes = store.addNote("Call Alex")
print("Total notes: \(totalNotes)")

store.listNotes()
```

Output (tested with Swift 6.4):

```text
Total notes: 2
- Buy milk
- Call Alex
```

This is a good use of `@discardableResult` because adding the note is the main action, while the new count is useful but optional.

## 10. Key Points

- `@discardableResult` lets callers ignore a function's return value without an unused-result warning.
- It does not remove or change the return value.
- It is best for functions where the side effect is primary and the return value is optional.
- It should not be used to hide poor API design or suppress meaningful warnings.
- Returning `Void` is often better when the result has no real value.
- Using `_ = ...` at one call site may be better than changing the whole API.

## 11. Practice Exercise

Create a `BankAccount` type with a method named `deposit`. The method should add money to the balance and return the new balance. Mark it so callers can ignore the returned value when they only care about updating the account.

- Create a struct called `BankAccount`.
- Add a stored property named `balance` of type `Double`.
- Add a mutating method `deposit` that takes an amount and returns the new balance.
- Call the method once without storing the result.
- Call it again and print the returned balance.

**Expected output:** The final printed value should show the updated balance after the second deposit.

**Hint:** Use `@discardableResult` above the method declaration, not at the call site.

```swift
struct BankAccount {
    var balance: Double = 0.0

    @discardableResult
    mutating func deposit(_ amount: Double) -> Double {
        balance += amount
        return balance
    }
}

var account = BankAccount()
account.deposit(50.0)

let updatedBalance = account.deposit(25.0)
print("Updated balance: \(updatedBalance)")
```

Output (tested with Swift 6.4):

```text
Updated balance: 75.0
```

## 12. Final Summary

`@discardableResult` is a small Swift attribute, but it has an important role in API design. It tells the compiler that a returned value may be ignored intentionally, which helps when a function's main purpose is a side effect and the returned value is only a convenience. Used well, it makes call sites cleaner and reduces unnecessary warning suppression code.

The key is moderation. Do not add `@discardableResult` to every function that returns something. If the result is essential, let Swift warn when it is ignored. If the result is optional and the action itself is the main reason the function exists, the attribute is often the right tool. A good next step is to compare this topic with other Swift attributes such as `@available` and `@escaping` so you can see how attributes help express API intent clearly.
