__gc/__close ordering

105 views
Skip to first unread message

Eleanor Bartle

unread,
Jan 21, 2026, 5:11:28 PM (5 days ago) Jan 21
to lua-l
Hi folx. I have a question which I haven't seen answered anywhere: how is the __close metamethod of an object ordered with respect to the __gc metamethod? That is, when an object is collected and its __gc method is run, is its __close method also run? If so, in what order? Conversely, when an object is closed and its __close metamethod is run, is its __gc method also run? Again, in what order? If neither is true, does that mean the __gc and __close metamethods must in general duplicate some of each other's code?

Relatedly, the coroutine library has a .close function as of 5.4, but this is not set as a __close metamethod on the thread type, that is

local f <close> = coroutine.create -- ...

is an error. Would it perhaps make sense to set this metamethod?

Gé Weijers

unread,
Jan 21, 2026, 7:21:05 PM (4 days ago) Jan 21
to lu...@googlegroups.com
On Wed, Jan 21, 2026 at 2:11 PM Eleanor Bartle <essenc...@gmail.com> wrote:
Hi folx. I have a question which I haven't seen answered anywhere: how is the __close metamethod of an object ordered with respect to the __gc metamethod? That is, when an object is collected and its __gc method is run, is its __close method also run? If so, in what order? Conversely, when an object is closed and its __close metamethod is run, is its __gc method also run? Again, in what order? If neither is true, does that mean the __gc and __close metamethods must in general duplicate some of each other's code?

__gc is only run when no local variable, global variable or table references an object. The call can be delayed arbitrarily long. If you exit the program with os.exit and don't request a final garbage collection then __gc may not be run at all.

__gc is run after __close, because in order for __close to be called the object has to be referenced from the stack and is therefore not garbage yet.

__close is run multiple times if you reference the object from multiple "local <close>" variables.

Sane code should use __gc to clean up release resources and not much else, because it's running at some random point in your program as it's called by the garbage collector.




Relatedly, the coroutine library has a .close function as of 5.4, but this is not set as a __close metamethod on the thread type, that is

local f <close> = coroutine.create -- ...

is an error. Would it perhaps make sense to set this metamethod?

 
Threads don't have a metatable by default, but you can add one for all coroutines by doing this:
do
    local dummy = coroutine.create(function()end)
    debug.setmetatable(dummy, { __close = coroutine.close })
end

I don't know whether this has any negative consequences. 

bil til

unread,
Jan 22, 2026, 2:45:32 AM (4 days ago) Jan 22
to lu...@googlegroups.com
> On Wed, Jan 21, 2026 at 2:11 PM Eleanor Bartle <essenc...@gmail.com> wrote:
> how is the __close metamethod of an object ordered with respect to the __gc metamethod?

_gc might be called only before _close, if you somehow "forgot" to
announce the object (which typcially will be userdata) to Lua ...
either by assigning the returned userdata reference to a Lua variable.
_close will then invoke, if this Lua variable gets killed.

Or if you use the userdata only internally in C, you must use
lua_setfield to add this userdata reference to the registry of your
lua state. I think _close might then be invoked when you kill this
reference by using lua_setfield for this registry reference again with
"nil value" to kill this reference.

... if you get _gc call before _close call, then somehow you did not
obeye such rules I would think... .

Gé Weijers

unread,
Jan 22, 2026, 7:58:56 AM (4 days ago) Jan 22
to lu...@googlegroups.com
On Wed, Jan 21, 2026 at 11:45 PM bil til <bilt...@gmail.com> wrote:
> On Wed, Jan 21, 2026 at 2:11 PM Eleanor Bartle <essenc...@gmail.com> wrote:
> how is the __close metamethod of an object ordered with respect to the __gc metamethod?

_gc might be called only before _close, if you somehow "forgot" to
announce the object (which typcially will be userdata) to Lua ...
either by assigning the returned userdata reference to a Lua variable.
_close will then invoke, if this Lua variable gets killed.

I use __close with regular tables all the time, for cleanup. It's not just for userdata objects. 

__close is called when a local variable with the "<close>" attribute referencing an object (usually a table or userdata) goes out of scope.
It's also used by the generic for loop to close the object that's the optional 4th value returned by an iterator.

__gc is called when the garbage collector determines that the table or userdata is no longer accessible by the program.

Unless you write some really ugly code, __gc will be the last function called before the object is collected, but you can 'revive' the object in __gc.

The following code manages to call the __gc and __close metamethods of a table repeatedly until you kill the program. Don't try this at home, kids!

local ref

local mt; mt = {
    __close = function(_)
        print"close"
    end,
    __gc = function(ob)
        print"gc"
        ref = ob
        setmetatable(ob, mt)
    end,
}

local object = {}
while true do
    do
        local _ <close> = setmetatable(object, mt)
        object = nil
    end

    while ref == nil do
        collectgarbage()
    end

    ref, object = nil, ref
end

 

Or if you use the userdata only internally in C, you must use
lua_setfield to add this userdata reference to the registry of your
lua state. I think _close might then be invoked when you kill this
reference by using lua_setfield for this registry reference again with
"nil value" to kill this reference.

... if you get _gc call before _close call, then somehow you did not
obeye such rules I would think... .


You can use the __close mechanism from C, using the Lua C api calls 'lua_toclose' and 'lua_closeslot'. I have never needed to.


--

Roberto Ierusalimschy

unread,
Jan 22, 2026, 11:31:25 AM (4 days ago) Jan 22
to lu...@googlegroups.com
> [...] If neither is true, does that mean the __gc
> and __close metamethods must in general duplicate some of each other's code?

Yes, often __close and __gc duplicate some of each other's code. For
instance, streams in Lua use exactly the same function for both:

> f = io.open("temp")
> getmetatable(f).__gc
function: 0x61bf602208b0
> getmetatable(f).__close
function: 0x61bf602208b0

Accordingly, the function should be prepared to be called multiple times.
('io.close' is almost the same function, too, except that it raises an
error if the file is already closed.)

As another example, auxiliary buffers in the C API also use the same
function for __close and __gc.

-- Roberto
Reply all
Reply to author
Forward
0 new messages