What does defer guarantee? What is the order of multiple defers?
Predict first
What does work() print?
func work() {
defer { print("A") }
defer { print("B") }
print("body")
}
work()
- body A B
- body B A
- A B body
Mental model. Defers are plates stacked on a spring. The last plate you put on is the first one that comes off.
defer runs when the current scope exits — by return, throw, break, or falling off the end. It runs even on the error path, which is why it is the right place for cleanup.
Multiple defers run LIFO: the last one registered runs first. A defer inside an inner block runs when that block exits, not at function end — the classic puzzle in Q27 of the bank.
Defers run when the scope exits, last registered first.
Code
func work() {
defer { print("A") }
defer { print("B") }
print("body")
}
func nested() {
defer { print("outer") }
do {
defer { print("inner") }
print("in do")
}
print("after do")
}
work()
nested()
body, B, A, in do, inner, after do, outer
Common traps
- “
deferruns at function return only.” It is scope-based. A defer in anifordoblock fires at the end of that block. - “
defercannot see the return value.” It cannot change the returned value after the return expression is evaluated, but it can read variables in scope. - Forgetting that
deferruns during a throw. That is the point — cleanup happens on both paths.
They might follow up with
- Can you
returnfrom inside adefer? No — that is a compile error. - Does a
deferin a loop run every iteration? Yes, if the loop body creates a scope — which it does. Each iteration registers and fires its own defer.
Related questions
- 1.8.2 try, try?, try! — and what is rethrows?
- 1.4.7 What is generic specialization? When does it not happen?
← What are typed throws (throws(MyError))? Why do they exist? What are consume, borrowing, and noncopyable types, at a high level? →