Using Lua 5.4’s <close> Attribute for Deterministic Resource Cleanup
Lua 5.4 introduces the <close> declarator, which ties a variable’s lifetime to its scope and automatically runs a __close metamethod, giving RAII‑style cleanup without extra boilerplate.
09 Aug 2026, 03:38 UTC

Problem: …
\nWhen a Lua function acquires a resource such as a file handle, a lock, or a custom object, the programmer must remember to release it before the function ends. If an early return, a break, or an error occurs, the release step can be skipped, leading to leaks or locked state.
\nHow Works
\nLua 5.4 adds the declarator. Writing local x = expr marks x as a to‑close variable. When the variable leaves its scope—by normal flow, break, return, or an unwinding error—Lua automatically looks for a __close metamethod on x’s value and invokes it. Errors raised inside __close are suppressed, so the metamethod should avoid failing or log errors internally.
Worked Example
\nlocal function write_log()\n local f = io.open('app.log', 'w')\n if not f then return end\n f:write('start\\n')\n -- Simulate an error condition\n if true then error('something went wrong') end\n f:write('end\\n')\nend\nEven if the error statement is triggered, the f variable goes out of scope, Lua calls f:__close (which for a file handle closes the underlying descriptor), and the file is properly closed. After the function returns, io.type(f) would return nil.
Trade‑offs and Limitations
\n- \n
- Requires Lua 5.4 or later; the
token is a syntax error on Lua 5.3 and earlier.\n - The
__closemetamethod must not raise an error; any error inside it is swallowed and may mask the original exception. \n - Tracking
locals adds a tiny runtime overhead.\n
Actionable Closing
\nUse for file handles, locks, or any resource that exposes a __close method returning nil or false on success. Verify the behavior with a Lua 5.4 interpreter: run the example, provoke an error inside the block, then check that io.type(f) returns nil after the function exits. If you need to support Lua 5.3, wrap the resource in a pcall-based helper or use a compatibility library that emulates with debug hooks.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.