Since functions are treated like any other value type in Lua, they can be assigned to variables and returned from other functions. They can also be attached to a scope with variables that follow that scope, making it a closure.
I have an implementation of the flood-fill algorithm that’s supposed to be as reusable as possible. For that purpose I’ve implemented it as a function that takes functions as arguments that define the graph the algorithm works on, as well as how it does it. The signature looks something like
function flood_fill(start_cell, f_get_neighbors, f_add_to_closed)
end
where the parameter names starting with “f_” indicate that they’re supposed to be functions. A call to flood_fill
could look like
local closed_set = Map3D.new() --a set of Vector3s
flood_fill(
start_cell,
function(cell) --f_get_neighbors
return {
Vector3.New(1, 0, 0),
Vector3.New(-1, 0, 0),
Vector3.New(0, 0, 1),
Vector3.New(0, 0, -1)
} --for a square grid, any other logic could be used to define any kind of graph
end,
function(cell) --f_add_to_closed
closed_set:vSet(cell, true)
end
)
Another pattern I sometimes use is factories. Factories make something. Often what they make is a function.
function fractalNoiseFactory(params)
--[[
Returns a fractal noise generator
]]
local noise = math.noise
local seed = params.seed or (e * r:NextInteger(-RANDOM_SEED_AMPLITUDE, RANDOM_SEED_AMPLITUDE))
local amplitude = params.amplitude or 1
... --other local variables
local function evaluate(x, y, z)
... --does something
end
return evaluate
end