Functions

9.1 Defining and Calling

local function add(a, b)
    return a + b
end

local multiply = function(a, b) return a * b end   -- anonymous function assigned to a variable

print(add(2, 3), multiply(4, 5))
-- add(1)                -- missing arguments are nil → error: attempt to perform arithmetic on a nil value
print(add(1, 2, 3))      --> 3 (extra arguments are discarded)

-- Call shortcuts with a single string or table argument
print "no parentheses"
local function config(t) return t end
config{width = 800, height = 600}

9.2 Multiple Return Values

local function min_max(t)
    local min, max = math.huge, -math.huge
    for _, v in ipairs(t) do
        if v < min then min = v end
        if v > max then max = v end
    end
    return min, max
end

local lo, hi = min_max({3, 1, 9, 4})
print(lo, hi)                       --> 1  9
print(min_max({5}))                 --> 5  5
print((min_max({3, 1, 9})))         --> 1 (parentheses truncate to one value)
local t = {min_max({3, 1, 9})}      --> {1, 9}
print(min_max({3, 1}), "end")       --> 1  end  (only the LAST expression in a list expands)

9.3 Variadic Functions

local function sum(...)
    local total = 0
    for _, v in ipairs({...}) do total = total + v end
    return total
end
print(sum(1, 2, 3, 4))              --> 10

local function count_args(...)
    return select("#", ...)          -- counts nils too
end
print(count_args(1, nil, 3))        --> 3
print(select(2, "a", "b", "c"))     --> b  c
print(select(-1, "a", "b", "c"))    --> c

local function pack_demo(...)
    local args = table.pack(...)    -- {n = count, ...} preserves nils (5.2+)
    for i = 1, args.n do print(i, args[i]) end
    return table.unpack(args, 1, args.n)   -- unpack (5.1: unpack)
end

local function log(fmt, ...)
    print(string.format("[LOG] " .. fmt, ...))
end
log("%s has %d items", "cart", 3)

9.4 Named Arguments and Defaults

local function create_window(opts)
    opts = opts or {}
    local width  = opts.width or 800
    local height = opts.height or 600
    local title  = opts.title or "Untitled"
    return string.format("%s (%dx%d)", title, width, height)
end
print(create_window{title = "Game", width = 1024})

9.5 Recursion and Proper Tail Calls

local function f lets f call itself recursively (it's sugar for local f; f = function ... end). local f = function ... f() ... end would refer to a global f inside the body.

local function factorial(n)
    if n <= 1 then return 1 end
    return n * factorial(n - 1)
end

local function fact_tail(n, acc)          -- proper tail call: no stack growth
    acc = acc or 1
    if n <= 1 then return acc end
    return fact_tail(n - 1, acc * n)       -- must be exactly `return f(args)`
end
print(fact_tail(20))                       --> 2432902008176640000
-- Tail calls reuse the stack frame, so even fact_tail(1e7) recurses without a stack overflow
-- (the integer result itself overflows and wraps around, but the recursion is safe).