Defer
defer registers a statement as a cleanup hook that must run before the current block is left. Nothing executes at registration; execution runs in reverse order. Resources with a Dispose protocol go through using; every other wrap-up scenario goes through defer.
Basic Form
Multiple defers run in reverse declaration order: the last registered runs first:
defer { print("the first-registered defer runs last"); }
defer { print("the last-registered defer runs first"); }
print("D");D
the last-registered defer runs first
the first-registered defer runs lastThe reverse order guarantees “last opened, first closed”, matching the nesting order of resource acquisition.
Block Scope
A defer attaches to the block it sits in, not to the whole function. When an inner block ends, its defers run:
print("A");
{
defer { print("inner block defer"); }
print("B");
}
print("C");A
B
inner block defer
CRelation to Return Values
A defer’s job is cleanup; the return value expression is evaluated at the return, and the defer cannot see that result:
func Expression() -> int
{
var n = 1;
defer { n = 99; }
return n + 0;
}n + 0 has already evaluated to 1 by the time of the return; the defer changing n afterwards does not touch it.
Statements Banned in the Body
A defer body must not use return, break, continue, or fail; using them raises MS4027:
error MS4027: 'return' must not be used inside a defer body.If cleanup hooks could jump on their own, the execution order would become impossible to reason about, so the language bans it outright.
Notes
defer statementtakes a single statement; the most common form isdefer { block }.- Every exit from a block that registered defers triggers them: on
return, onfail(including a failure propagating through this frame from a called function), or on the block simply ending, the defer runs before the block exits. When main exits with an error at the top level, the defers in main run first all the same. The only path where they do not run is a process-level crash; the terminal state runs no cleanup. - A defer runs when the block it was registered in exits: an inner block’s defer does not wait for the function to end.
- out parameters in a defer are not written back on the fail path; output parameters on a failure path cannot be relied on.
