--- name: finally signature: 'finally BLOCK' since: 5.36 status: documented categories: ["Control flow"] --- ```{index} single: finally; Perl built-in ``` *[Control flow](../perlfunc-by-category)* # finally Run cleanup code on the way out of a `try`/`catch`, whether the body succeeded, threw, or jumped away. `finally` introduces a third block that can follow a `try`/`catch` pair. Its body runs exactly once, after the `try` body completes — however it completes. A normal fall-through, an exception caught by the `catch`, an exception that escapes because there is no matching `catch`, a `return` from the enclosing sub, a `goto`, a `last`/`next`/ `redo` leaving the enclosing loop: every one of these routes through the `finally` block before control continues. The pattern is equivalent to scheduling a `defer` block at the top of the `try`, with a syntax that keeps the cleanup visually attached to the try/catch it belongs to. ## Synopsis ```perl use feature 'try'; no warnings 'experimental::try'; try { BODY } catch ($e) { HANDLE } finally { CLEANUP } ``` ## What you get back `finally` has no return value. The final expression of the block is evaluated for its side effects and then discarded — it does **not** contribute to the value of the enclosing `try`/`catch` expression, even if the whole construct is the last statement of a sub or `do` block being used to produce a value. ```perl my $v = do { try { compute() } catch ($e) { $DEFAULT } finally { log("done"); 999 } # 999 is discarded }; # $v is either compute()'s value or $DEFAULT ``` Use `finally` for cleanup that has to happen, not for computing a result. ## Feature status `finally` is part of the `try` feature, but unlike `try` and `catch` (which became non-experimental in Perl 5.40) it remains experimental in Perl 5.42. Using it without silencing the warning produces: ```text finally is experimental at ... line N. ``` Enable the feature and silence the warning together: ```perl use feature 'try'; no warnings 'experimental::try'; ``` Because the warning category is `experimental::try` — the same one that `try`/`catch` used to emit — silencing it enables `finally` without re-enabling warnings on the now-stable parts of the feature you do want diagnostics for. ## When the block runs The contract is "on the way out, no matter how." Concretely, `finally` runs after each of the following: - **Normal completion of `try`**. The `try` body fell off the end or returned its last expression value; `finally` runs next, then the statement after the `try` construct. - **Exception caught by `catch`**. The `try` body threw, the `catch` matched and handled it; `finally` runs after the `catch` body. - **Exception not caught**. There is no `catch`, or the `catch` itself re-threw with [`die`](die); `finally` still runs, then the exception continues propagating to the next dynamic [`eval`](eval)/`try` outward. - **`return` inside `try` or `catch`**. The enclosing sub is about to return; `finally` runs, then the return takes effect. - **Loop control (`last`, `next`, `redo`) inside `try` or `catch`**. `finally` runs, then the loop control takes effect in the enclosing loop. - **`goto &sub` or `goto LABEL` leaving the `try`**. `finally` runs before the jump completes. The ordering matters: if the `catch` itself raises a new exception, `finally` still runs, and the new exception is the one that propagates (the original is replaced, just as with any `die` inside a handler). ## Restrictions on the block body A `finally` block is a cleanup point, not a control-flow redirect. Perl rejects any control-flow statement that would try to override how the construct is already unwinding: - **`return`** inside `finally` is a syntax / compile-time error. - **`goto`** inside `finally` is a syntax / compile-time error. - **Loop controls** (`last`, `next`, `redo`) targeting a loop *outside* the `finally` block are rejected. Inside a plain loop that is *contained* in the `finally` body, the loop controls apply to that inner loop as normal — the restriction is on leaving the `finally` block, not on looping inside it. [`die`](die) is permitted. A `finally` block that throws replaces any in-flight exception from the `try`/`catch` with the new one. This is usually a bug (you lose the original failure), so guard cleanup code that might itself fail: ```perl finally { eval { $fh->close }; # swallow close errors during cleanup } ``` ## Relationship to `defer` `finally BLOCK` is "`defer BLOCK` placed at the top of the `try`, attached instead to the try/catch pair." Both run on every exit path from their containing scope; both forbid the same control-flow statements in their body; both discard their return value. The difference is scope attachment: - `defer` attaches to the *innermost enclosing block* and fires on that block's exit. It is the general-purpose cleanup primitive and works in any block. - `finally` attaches to the *`try`/`catch` construct* and fires when that construct is done. It is syntactic sugar for the common case where the cleanup is specifically about what the `try` was doing. ```perl # These two are behaviourally equivalent: try { my $fh = acquire(); defer { release($fh) } work($fh); } catch ($e) { warn $e } try { my $fh = acquire(); work($fh); } catch ($e) { warn $e } finally { release_last() } # if $fh were available here ``` Note one practical consequence: variables declared inside the `try` body go out of scope before `finally` runs. If the cleanup needs a resource allocated inside the `try`, either declare it in an outer scope, or use `defer` inside the `try` where the variable is live. ## Examples Always close a handle, even on error: ```perl use feature 'try'; no warnings 'experimental::try'; open my $fh, '<', $path or die "open $path: $!"; try { process($fh); } catch ($e) { warn "processing failed: $e"; } finally { close $fh; } ``` Release a lock regardless of outcome: ```perl my $lock = $mutex->lock; try { critical_section(); } finally { $lock->release; } ``` Observability: log every exit path: ```perl try { run($job); } catch ($e) { $job->mark_failed($e); die $e; # re-throw; finally still runs } finally { metrics->tick('job.exit', $job->id); } ``` Value-producing `try`/`catch`, with `finally` for cleanup only: ```perl my $result = do { try { fetch($url) } catch ($e) { $CACHED } finally { close_connection() } }; # $result is fetch() or $CACHED; finally's value is never used ``` ## Edge cases - **`catch` can be omitted.** `try { ... } finally { ... }` is legal and runs `finally` on both normal and exceptional exit; the exception then propagates as if no `try` were there. - **Nested `try`/`finally`**: `finally` blocks fire innermost-first as scopes unwind, matching `defer` semantics. - **Exception inside `finally`**: replaces any in-flight exception. The original is lost unless you captured it in the `catch` first. - **[`$@`](../perlvar) during `finally`**: not reliable for "what just happened." If the `finally` needs to know whether it is running after success or failure, set a flag in the `catch` block and inspect it: ```perl my $failed; try { risky() } catch ($e) { $failed = $e; die $e } finally { if ($failed) { rollback() } else { commit() } } ``` - **Global destruction**: `finally` blocks registered by a `try` that is still active when the interpreter starts tearing down run, but the same caveats as [`die`](die) inside `DESTROY` apply — keep the body defensive. - **Parse requires the feature**: without `use feature 'try'`, the word `finally` is not a keyword and parses as a bareword function call, which usually produces a confusing unrelated error. Always enable the feature before using the syntax. ## Differences from upstream Fully compatible with upstream Perl 5.42. ## See also - [`try`](try) — introduces the block whose exit `finally` hooks; see *Try Catch Exception Handling* in perlsyn - [`catch`](catch) — the optional middle block that handles exceptions thrown by `try`; `finally` runs after it either way - [`defer`](defer) — the general-purpose "run on scope exit" block; `finally` is `defer` attached to a `try`/`catch` pair - [`die`](die) — the only way to cause the `catch` branch to fire; a `die` inside `finally` replaces any in-flight exception - [`eval`](eval) — the older exception-catching mechanism; `try`/ `catch`/`finally` supersede the common `eval { ... }; if ($@)` idiom with cleaner scoping and proper control-flow semantics