Swift @discardableResult - Silence Unused Result Warnings

September 19, 2026

Swift treats a returned value as something you probably meant to keep. If you call a function that produces a result and never use it, the compiler flags the call:

func addTrack(_ title: String) -> Int {
    // ...
    return 0
}

addTrack("Intro")
// ⚠️ Result of call to 'addTrack' is unused

Most of the time, that warning is a helpful nudge. But some APIs return a value as a convenience, such as an index, an identifier, or the modified instance itself. Many callers have no reason to look at it. For those functions, the warning becomes noise, and noise trains developers to ignore the Issue navigator.

The @discardableResult attribute lets the author of an API declare, once and in one place, that ignoring the return value is a normal way to call it.


Declaration

Place the attribute directly before the function or method declaration:

@discardableResult
func addTrack(_ title: String) -> Int

That's the whole syntax. There are no arguments and no configuration.


Basic Example

Consider a small playlist type. Appending a track returns the new track's position, which is handy if you want to select or animate the new row, but pointless if you're just loading data.

struct Playlist {
    private(set) var tracks: [String] = []

    /// Adds a track to the end of the playlist.
    ///
    /// - Parameter title: The title of the track to add.
    /// - Returns: The index of the new track. The result can be ignored.
    @discardableResult
    mutating func append(_ title: String) -> Int {
        tracks.append(title)
        return tracks.count - 1
    }
}

var playlist = Playlist()

playlist.append("Intro")               // No warning.
let position = playlist.append("Outro") // Result put to use.

Both call sites are valid, and the compiler stays quiet in each case.


Fluent interfaces and method chaining

The attribute is a natural fit for builder-style APIs that return Self so calls can be chained. Without it, every standalone configuration call would produce a warning:

final class RequestBuilder {
    private var headers: [String: String] = [:]

    @discardableResult
    func header(_ name: String, value: String) -> Self {
        headers[name] = value
        return self
    }
}

let builder = RequestBuilder()

// Standalone calls: no warnings.
builder.header("Accept", value: "application/json")
builder.header("X-Trace-ID", value: "42")

// Chained calls read just as well.
builder
    .header("Accept", value: "application/json")
    .header("X-Trace-ID", value: "42")

Asynchronous and throwing functions

@discardableResult composes with async and throws. It suppresses only the unused-result diagnostic. Any try or await your function requires remains mandatory.

struct UploadReceipt { let id: String }

@discardableResult
func upload(_ data: Data) async throws -> UploadReceipt {
    // ...
    return UploadReceipt(id: "abc123")
}

func save(_ data: Data) async throws {
    try await upload(data)                // No unused-result warning.
    let receipt = try await upload(data)  // Result available when needed.
    print(receipt.id)
}

Note Error handling stays visible at the call site. A discardable result never lets a failure slip by unnoticed, because throwing is expressed with throws, not with the return value.


Choosing Between the Attribute and _ =

Swift gives you two ways to say "I know there's a result, and I don't need it." They answer different questions.

@discardableResult _ = call()
Applied by The API author The caller
Written Once, at the declaration At every call site
Meaning "Ignoring this result is normal." "I'm ignoring this result on purpose, this time."
Best for Convenience returns that most callers skip Results that usually matter, but not right here

Use the attribute when most callers won't need the value. Use _ = when the result matters in general and you're making a deliberate exception:

_ = try? await upload(data) // A conscious, visible decision.

Precedent in the Standard Library

You've likely relied on this attribute without noticing. Several familiar APIs return a value that's useful on occasion and easy to skip the rest of the time:

  • Array.remove(at:) returns the element it removed.
  • Set.insert(_:) reports whether the insertion happened and which member is in the set.
  • Dictionary.updateValue(_:forKey:) returns the value that was replaced, if any.

Each is annotated so that a bare call compiles cleanly. That's the same design bar to apply to your own code: the return value is a bonus, not a duty.


When Not to Use It

The attribute silences a diagnostic, so it's worth asking what that diagnostic was protecting. Skip @discardableResult when ignoring the value is likely a bug.

Pure functions. If a function's only purpose is to compute a value, dropping the value means the call did nothing. This is why sorted() and map(_:) deliberately keep the warning.

Results that carry failure. A return value that reports success or failure invites silent errors:

// ❌ A failed save disappears without a trace.
@discardableResult
func save() -> Bool {
    // ...
}

Prefer a throwing function, so failures can't be overlooked:

// ✅ Failure is explicit and enforced by the compiler.
func save() throws {
    // ...
}

A quick test: "If a caller ignores this value, could the program end up in a wrong or misleading state?" If the answer is yes, leave the warning in place.


Behaviors Worth Knowing

Protocol requirements. The compiler evaluates the attribute on the declaration a call actually resolves to. If callers use your API through a protocol type or a generic constraint, put @discardableResult on the protocol requirement as well as on the conforming implementations.

protocol Queueing {
    @discardableResult
    mutating func enqueue(_ job: String) -> Int
}

Functions returning Void. There's no result to discard, so the attribute has no effect. Adding it is harmless but redundant.

Function values. @discardableResult is a declaration attribute. A closure stored in a variable doesn't carry it, so an unused result from calling that closure still needs _ =.

Warnings as errors. If your project builds with warnings treated as errors, an unused result is a failed build, not just a yellow triangle. In that setup, deciding which functions are discardable becomes an API design decision rather than a cosmetic one.

Objective-C interop. Objective-C methods imported into Swift are generally treated as discardable unless they're explicitly annotated to warn on unused results. That's why some Cocoa calls never trigger the warning.


Documenting a Discardable Result

The attribute tells the compiler the result is optional. Tell your readers too. Use a Returns field in your documentation comment and state plainly that the value can be ignored:

/// Registers a handler for the given event.
///
/// - Parameter handler: The closure to call when the event fires.
/// - Returns: A token you can use to unregister the handler.
///   The token can be ignored if you never need to unregister.
@discardableResult
func observe(_ handler: @escaping () -> Void) -> ObservationToken {
    // ...
}

Xcode's Quick Help surfaces this text, so the contract is visible right where developers need it.


A Brief History

Swift 2 used an opt-in attribute, @warn_unused_result, to flag functions whose results mattered. Swift 3 inverted the model (Swift Evolution proposal SE-0047): every non-Void function now warns on an unused result by default, and @discardableResult is the explicit opt-out. Treating results as meaningful unless declared otherwise makes accidental omissions much easier to catch.


Final Thoughts

  • @discardableResult marks a function or method whose return value may be safely ignored.
  • It removes the "Result of call to … is unused" warning without changing behavior.
  • It's ideal for convenience values: indices, identifiers, tokens, and Self in fluent APIs.
  • It doesn't remove try or await requirements.
  • Prefer _ = when a result normally matters and you're skipping it only once.
  • Don't apply it to pure functions or to return values that signal failure. Use throws for errors.
  • Annotate protocol requirements when callers use the protocol type.
  • Document the optional result in a Returns field.

Used deliberately, the attribute keeps your call sites quiet and your warnings meaningful, so a yellow triangle in Xcode is worth reading again.

Thank you for reading. If you have any questions feel free to follow me on X and send me a DM. If this article helped you, Buy me a coffee.