(rontolisp) docs
← Special Forms

unwind-protect

(unwind-protect protected cleanup...)

Evaluates the protected form and returns its value, running the cleanup forms on every exit from it: a normal return, an error unwind, and a return/return-from non-local exit. The cleanup values are discarded -- their count included, so a protected form returning multiple values answers all of them however many the cleanup returns. A cleanup form that itself signals replaces the pending exit (the newer error wins, as in Common Lisp).

unwind-protect is supported on every backend except --no-gc (a compile error there). On the wasm-GC backends (Preview 1 and --component) it compiles through the WebAssembly exception-handling proposal, so running a program that uses it needs wasmtime 37+; a program without catching/cleanup forms is byte-identical to before and keeps its usual command line. Divergence: the cleanups run on a signaled error unwind (error/signal), but a runtime trap (a (car 5)-style type failure, integer division by zero) still aborts the instance without running them — the interpreter and the JVM run cleanups for those too. The with-* macros (with-open-file, with-output-to-string, with-input-from-string, and the usocket:with-* family) expand over unwind-protect on every backend, so they release their handle on every exit; on wasm-GC a with-* program therefore also compiles in EH mode.

A cleanup that returns its own values -- (values), the idiomatic "I return nothing" of a release helper, included -- does not truncate the protected form's:

The cleanup also runs when the protected form exits early via return:

Because an uncaught error aborts the program, the error path is shown statically:

CL-USER> (unwind-protect (error "boom") (print :cleaned))
:cleaned
Error: boom