How are anonymous/unreachable functions and variables kept?

Forgive this perhaps naive question from an experienced scripter.
Okay so suppose we do something like this.

function AddNewObject(obj)

 local DescendantsAdded = 1 -- Gets garbage collected

 print(DescendantsAdded)

end

workspace.ChildAdded:Connect(AddNewObject)

So here, DescendantsAdded stops existing and gets garbage collected because it goes out of scope.

Here something different happens however.

function AddNewObject(obj)

 local DescendantsAdded = 0 -- Does not get garbage collected?

 obj.DescendantAdded:Connect(function(obj2) -- Anonymous function?

  DescendantsAdded += 1
  print(DescendantsAdded) -- Variable keeps existing???

 end

end

workspace.ChildAdded:Connect(AddNewObject)

Now DescendantsAdded seems to exist forever, at least, until we destroy the object or disconnect the function from it.

The function also is not assigned to a variable, so it’s anonymous.

Where do these exist? In what part of memory is this kept and can it still be accessed in some other way?

I feel like I should know this since I’ve been on Roblox for like 10 years but somehow I still don’t know how exactly this works.

2 Likes

First, values such as numbers and booleans don’t get garbage collected. They are stored in virtual registers which the compiler chooses for each variable. Only functions, tables and userdata require garbage collection.

When a function uses a local variable from a higher scope, it just grabs and works with the variable’s register (called an upvalue in the function proto).

Here’s some Lua 5.1 bytecode that should help:

local v = 1

local function f()
	print(v)
end

f()
main <input-file.lua:0,0> (6 instructions, 24 bytes at 1b553702_29ec04fe)
0+ params, 3 slots, 0 upvalues, 2 locals, 1 constant, 1 function
function main(...) --line 1 through 7
1	LOADK	0 -1	; 1
2	CLOSURE	1 0	function f() @ 0e68dea3_294c04c8
3	MOVE	0 0	
4	MOVE	2 1	
5	CALL	2 1 1	
6	RETURN	0 1	
end

function <input-file.lua:3,5> (4 instructions, 16 bytes at 0e68dea3_294c04c8)
0 params, 2 slots, 1 upvalue, 0 locals, 1 constant, 0 functions
function f() --line 3 through 5
1	GETGLOBAL	0 -1	; print
2	GETUPVAL	1 0	; v
3	CALL	0 2 1	
4	RETURN	0 1	
end
2 Likes

Oh thanks for this helpful insight (and pardon my late response).

Looking at this does have me wonder if anonymous functions/variables could overflow Lua’s 200 local variable limit somehow and if it would be save to use anonymous variables for storing data about an entity or character like states.