Swift
@autoclosure
Swift programming
closures
iOS development

How to use Swift autoclosure

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

@autoclosure in Swift lets a function accept an expression and automatically wrap that expression in a closure. The main benefit is cleaner call-site syntax for APIs that want lazy evaluation but do not want callers to write an explicit closure every time.

What @autoclosure Actually Does

Without @autoclosure, a function that wants delayed execution usually looks like this:

swift
1func logIfNeeded(_ message: () -> String) {
2    let shouldLog = false
3    if shouldLog {
4        print(message())
5    }
6}
7
8logIfNeeded({ "expensive message" })

That works, but the call site is noisy. With @autoclosure, Swift creates the closure for you:

swift
1func logIfNeeded(_ message: @autoclosure () -> String) {
2    let shouldLog = false
3    if shouldLog {
4        print(message())
5    }
6}
7
8logIfNeeded("expensive message")

The expression is not evaluated until message() is called inside the function.

Why Lazy Evaluation Matters

The feature is useful when computing the argument might be expensive or unnecessary. Assertions are a classic example. You do not want to build a large error string unless the assertion fails.

swift
1func myAssert(_ condition: @autoclosure () -> Bool,
2              _ message: @autoclosure () -> String) {
3    if !condition() {
4        print("Assertion failed: \(message())")
5    }
6}
7
8let value = 3
9myAssert(value > 10, "Expected value greater than 10, got \(value)")

At the call site, this reads like an ordinary function call even though both arguments are deferred.

Common Use Cases

@autoclosure is a good fit when:

  • the function should decide whether to evaluate an argument
  • you want the API to read naturally
  • the deferred expression is simple and single-purpose

This is why Swift standard library APIs such as assert and precondition use the same idea.

Another example is a nil-coalescing-style helper:

swift
1func valueOrFallback<T>(_ value: T?, fallback: @autoclosure () -> T) -> T {
2    if let value = value {
3        return value
4    }
5    return fallback()
6}
7
8let name: String? = nil
9print(valueOrFallback(name, fallback: "Guest"))

The fallback expression is only evaluated when the optional is actually nil.

Escaping Autoclosures

By default, an autoclosure is non-escaping. If you want to store it and run it later, you must mark it as @escaping too.

swift
1class DelayedPrinter {
2    private let action: () -> String
3
4    init(action: @autoclosure @escaping () -> String) {
5        self.action = action
6    }
7
8    func run() {
9        print(action())
10    }
11}
12
13let printer = DelayedPrinter(action: "Hello later")
14printer.run()

This is more advanced, but it shows that @autoclosure affects how the argument is written, not what closures are capable of doing.

When Not to Use It

@autoclosure is not a general replacement for closures. It is best for simple delayed expressions. If the caller needs parameters, multiple statements, or visible control flow, a normal closure is clearer.

For example, this is not a good fit for @autoclosure:

  • long computations
  • side-effect-heavy operations
  • callbacks with custom logic

In those cases, hiding the closure can make the API more confusing rather than more elegant.

Common Pitfalls

The biggest pitfall is forgetting that the expression is delayed. If the expression has side effects, those side effects happen only when the function evaluates the closure.

Another issue is overusing @autoclosure for fancy APIs. A little syntactic sugar is helpful, but too much makes evaluation order harder to see.

Developers also sometimes assume @autoclosure means memoization. It does not. If the function calls the closure twice, the expression runs twice.

Finally, if you need to store the autoclosure for later use, remember to mark it @escaping. Otherwise the compiler will reject the code.

Summary

  • '@autoclosure automatically wraps an expression in a closure.'
  • It is mainly used for lazy evaluation with cleaner call-site syntax.
  • Assertion-style APIs are a classic use case.
  • Use @escaping too if the autoclosure must be stored and called later.
  • Avoid it when a normal closure would make control flow or side effects clearer.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.