← Back to AILP Home

Drop / RAII

Nitpick's Drop mechanism is the opt-in RAII layer that auto-cleans-up resources at scope exit. Importing stdlib/drop.npk enables drop emission for a fixed set of resource regions — wild struct bindings, wildx pointer bindings, HandleArena handles, and JitFn pages — without changing the source-level spelling of those regions.

Without the import, those bindings keep the v0.29.2-and-earlier explicit-cleanup contract: you call npk_free / wildx_free / HandleArena.destroy / Jit.free yourself, and ARIA-014 fires on leaks. Drop is purely additive.

Quick reference

With use "drop.npk".*; Auto-emit at scope end
wild T:x = T{ ... }; npk_free(x)
wildx T->:p = wildx_alloc(N); npk_wildx_free(p)
int64:a = HandleArena.create(); npk_handle_arena_destroy(a)
wildx int8->:f = Jit.compile_add_i32(); npk_wildx_free(f)

Each region has its own opt-in sentinel struct (NitpickWildRaii, NitpickWildxRaii, NitpickHandleArenaRaii, NitpickJitFnRaii). The compiler keys on the presence of each impl:Drop:for:NitpickXxxRaii declaration. They all currently flip on the same drop.npk import; a future cycle may let a program enable one without the others.

When Drop runs

Drop calls fire at every scope-exit path:

  1. Fall-through — the block reaches its closing } without a terminator.
  2. pass v — early successful exit from a function.
  3. fail e — early TBB-error exit.
  4. return Result{...} — early return inside a fallible function.

Order within a scope is reverse declaration order (DROP-DEC-003). Across nested scopes, drops walk innermost-out. Drops always run before defer blocks (DROP-DEC-010).

When Drop does not run

Comparison: Drop vs failsafe vs explicit free

Mechanism Runs on Order Opt-in
Drop fall-through, pass, fail, return reverse decl use "drop.npk".*;
defer same as Drop reverse defer always available
failsafe fail propagation in main top of main body always available
Explicit free wherever you write it source order always available

Drop and defer are not mutually exclusive — a function may have both. Drops run first, defers run after. Inside a single scope, Drop touches only the four supported region shapes; defer runs arbitrary user code.

Chapters

  1. README — this page.
  2. Surfaceimpl:Drop:for:T, the drop method shape, what's allowed and what isn't.
  3. Regions — Drop for wild / wildx / Handle / Arena / JitFn. The RAII-vs-explicit decision table.
  4. Ordering — block reverse order, struct-field reverse order, pass / fail semantics, failsafe interaction, drop-before-defer.
  5. Pitfalls — moves out of bindings (no drop), destructor failure, drop-during-drop, hard exit, the Jit_compile_* forcing-function gotcha.
  6. NLL#[nll_drop] function attribute, last-use early-drop, #[lexical_drop] per-binding override, ARIA-052, borrow-lifetime tightening (v0.31.7.x).
  7. FAQ — RAII vs manual, NLL Q&A, why no Drop for primitives, can drop allocate? can it pass?

See also

Validation snapshot (v0.29.7)