--- name: defer signature: 'defer BLOCK' since: 5.36 status: documented categories: ["Control flow"] --- ```{index} single: defer; Perl built-in ``` *[Control flow](../perlfunc-by-category)* # defer Schedule a block to run when the enclosing scope exits, for any reason. `defer` is a flow-control keyword, not a function. Writing `defer { ... }` inside a scope records the block for later execution; when control leaves the enclosing block — by falling off the end, by [`return`](return), by [`die`](die), by `goto`, or by a loop-control statement ([`next`](next), [`last`](last), [`redo`](redo)) — the stored block runs on the way out. It is the standard idiom for pairing acquisition with release (open/close, lock/unlock, push/pop) without relying on object destructors or wrapping every path in [`eval`](eval). The feature is **experimental** and must be enabled. Either opt in explicitly or pick up the bundle: ```perl use feature 'defer'; # explicit use v5.36; # bundle — enables defer among others ``` Under `use warnings 'experimental::defer'` (or plain `use warnings`) the first use emits an experimental warning. Silence it with `no warnings 'experimental::defer'` once you have decided to rely on the feature. ## Synopsis ```perl defer BLOCK ``` `defer` takes a brace-delimited block and nothing else. There is no expression form, no filehandle form, and no return value — the statement exists for its side effect on scope exit. ## What you get back `defer` is a statement, not an expression. It contributes no value to its surrounding context. The block's own return value is discarded when it runs at scope exit. ## When the deferred block runs The deferred block is invoked **once**, when control leaves the directly enclosing block, regardless of how control leaves: - normal fallthrough off the end of the block, - explicit [`return`](return) from the containing subroutine, - an exception thrown by [`die`](die) or propagated from a called sub, - `goto` out of the block, - loop control via [`next`](next), [`last`](last), or [`redo`](redo). If the flow of execution never reaches the `defer` statement itself, the block is **not** enqueued and does not run. This is the direct opposite of an `END` phaser, which the compiler enqueues unconditionally: ```perl use feature 'defer'; { defer { say "This will run"; } return; defer { say "This will not"; } # never reached, never scheduled } ``` ## LIFO ordering Multiple `defer` blocks in the same scope run in **last-in, first-out** order — the most recently scheduled block runs first. This matches the natural nesting of resource acquisition: the last thing acquired is the first thing released. ```perl use feature 'defer'; { defer { say "1"; } defer { say "2"; } defer { say "3"; } } # prints 3, then 2, then 1 ``` ## Global state it touches None directly. The deferred block sees interpreter globals ([`$_`](../perlvar), [`$!`](../perlvar), [`$@`](../perlvar), selected filehandle, etc.) with whatever values they hold **at the moment the block runs**, not at the moment it was scheduled. A `defer` that wants to preserve `$!` or [`$@`](../perlvar) across cleanup must save and restore them itself — otherwise a system call inside the block will clobber them and the caller of the enclosing sub will see the overwritten values. ```perl defer { local ($!, $@); close $fh; # clobbers $! on failure — local'd copy absorbs it } ``` ## Examples Pair an `open` with its `close`, guaranteed to run even on `die`: ```perl use feature 'defer'; sub read_config { open my $fh, "<", "config.ini" or die "open: $!"; defer { close $fh; } while (<$fh>) { ... } # close $fh runs here on fallthrough, on return, and on die. } ``` Unlock a shared resource on every exit path: ```perl use feature 'defer'; sub critical_section { $lock->acquire; defer { $lock->release; } do_work(); # release runs on fallthrough return if $shortcut; # release runs before the return completes die "boom" if $bad; # release runs, then the exception propagates } ``` LIFO cleanup of nested resources — the outer resource is released last, which is usually what you want: ```perl use feature 'defer'; sub copy_file { open my $in, "<", $src or die "open $src: $!"; defer { close $in; } open my $out, ">", $dst or die "open $dst: $!"; defer { close $out; } print {$out} $_ while <$in>; # close $out runs first, then close $in. } ``` Temporarily adjust interpreter state and restore it on exit without using [`local`](local): ```perl use feature 'defer'; sub with_separator { my $saved = $,; $, = " | "; defer { $, = $saved; } print @_, "\n"; } ``` ## Edge cases - **Conditional scheduling**. A `defer` statement only schedules its block when control actually reaches it. An early [`return`](return) or [`die`](die) that happens before the `defer` line leaves nothing to run. Place the `defer` immediately after the paired acquisition so they cannot become separated by an intervening failure. - **Once scheduled, always runs**. There is no mechanism to un-schedule a `defer` block. If the acquisition that the block releases has failed, either do not schedule the `defer` (keep it after the success check) or make the block idempotent so a redundant release is harmless. - **No control-flow escape from the block**. A `defer` block may throw an exception, but it may **not** [`return`](return) from the enclosing sub, `goto` a label outside itself, or run [`next`](next), [`last`](last), or [`redo`](redo) for a loop that encloses the `defer`. Those constructs are fine *inside* the `defer` when they act on loops **contained entirely within** the block's own body: ```perl defer { foreach (1 .. 5) { last if $_ == 3; } # permitted } foreach (6 .. 10) { defer { last if $_ == 8; } # forbidden } ``` - **Exception during exception unwind**. If the `defer` block is running because an exception is propagating and the block itself throws, the language does not specify the resulting exception — only that the caller will see one. Do not rely on which exception wins. Wrap risky cleanup in [`eval`](eval) if you need both signals preserved. - **Exceptions propagate normally**. An exception thrown by a `defer` block that is running for any other reason (normal exit, return, loop control) propagates to the caller exactly like any other exception. A failing `close` in cleanup can therefore turn a successful-looking function into a caller-visible `die`. - **`$@` and `$!` inside the block**. On the exception-driven exit path, [`$@`](../perlvar) holds the in-flight exception while the `defer` block runs. Reading it is fine; replacing it changes what the caller sees after the unwind completes. - **Scope granularity**. `defer` binds to the **immediately** enclosing block, not to the enclosing sub. A `defer` inside `if (...) { defer { ... } }` runs when the `if` block exits, not when the sub returns. Put the `defer` at subroutine scope if you want subroutine-exit semantics. - **Experimental warning**. Under `use warnings` the first occurrence warns. Opt in deliberately with `no warnings 'experimental::defer'` once you have committed to the feature. - **Not available without the feature guard**. Without `use feature 'defer'` (or a bundle that enables it), `defer { ... }` is parsed as a call to a subroutine named `defer` followed by a block — almost certainly not what you meant, and usually a compile-time error. ## Differences from upstream Fully compatible with upstream Perl 5.42. The feature remains marked experimental in pperl to mirror upstream's classification; behaviour (scheduling on statement execution, LIFO order, exception propagation, restrictions on control-flow escape) matches Perl 5.42. ## See also - [`eval`](eval) — the established tool for turning exceptions into return values; `defer` complements it by guaranteeing cleanup without an explicit `eval` wrapper on every path - [`die`](die) — one of the exit paths that triggers deferred blocks; read alongside `defer` when designing cleanup - [`return`](return) — another exit path; a `defer` scheduled before a `return` runs before the caller resumes - [`local`](local) — the other idiom for scoped state restoration; pick `local` for dynamic scoping of a single variable, `defer` for arbitrary cleanup actions - [`$@`](../perlvar) — current exception; visible inside a `defer` block running on the exception-unwind path - [`$!`](../perlvar) — system errno; easily clobbered by cleanup syscalls, `local`-ise inside the deferred block if the caller needs it preserved