Nanfeng

Notes on software development, code, and curious ideas

Understanding Closures in Lua

A closure is a function together with the external local variables it captures. The captured variables remain alive after their original block returns.

1
2
3
4
5
6
7
8
9
10
11
local function newCounter(start)
local value = start or 0
return function(step)
value = value + (step or 1)
return value
end
end

local nextValue = newCounter(10)
print(nextValue()) -- 11
print(nextValue(5)) -- 16

Each call to newCounter creates a separate value. Multiple closures created in the same call can deliberately share one variable:

1
2
3
4
local function newBox(value)
return function() return value end,
function(nextValue) value = nextValue end
end

Higher-order functions

Functions are ordinary values in Lua, so they can be arguments and results:

1
2
3
4
5
6
local function greaterThan(limit)
return function(value) return value > limit end
end

local isLarge = greaterThan(100)
print(isLarge(120))

This is useful for event callbacks, iterators, configuration, memoization, and private object state.

Loop capture

When callbacks are created in a loop, capture a per-iteration local if the code must work consistently across Lua versions and transformations:

1
2
3
4
5
local callbacks = {}
for i = 1, 3 do
local current = i
callbacks[i] = function() return current end
end

Closures can extend the lifetime of large tables or resources accidentally. If a long-lived callback needs only one field, capture that value instead of the entire object, and unregister callbacks when their owner is destroyed.

+