Lua Functions

Function Basics

Definition and calling
-- Named function
local function greet(name)
  return "Hello, " .. name
end

-- Anonymous function assigned to variable
local square = function(x) return x * x end

-- Multiple return values
local function parse_endpoint(endpoint)
  local host, port = endpoint:match("(.+):(%d+)")
  return host, tonumber(port)
end

local host, port = parse_endpoint("10.50.1.40:8200")
print(host, port)    -- 10.50.1.40    8200

-- Discard return values
local _, port_only = parse_endpoint("10.50.1.40:8200")

Variadic Functions

Variable arguments with …​
-- Variadic function
local function log(level, ...)
  local args = { ... }
  local msg = table.concat(args, " ")
  print(string.format("[%s] %s", level, msg))
end

log("INFO", "Server", "started", "on", "port", "8080")
-- [INFO] Server started on port 8080

-- select() with varargs
local function count_args(...)
  return select("#", ...)              -- number of args (including nil)
end

local function first_arg(...)
  return (select(1, ...))             -- first arg
end

Closures

Functions capture enclosing scope
local function make_counter(start)
  local count = start or 0
  return {
    increment = function()
      count = count + 1
      return count
    end,
    get = function()
      return count
    end,
  }
end

local c = make_counter(10)
print(c.increment())    -- 11
print(c.increment())    -- 12
print(c.get())           -- 12

-- Iterator factory
local function range(start, stop, step)
  step = step or 1
  local i = start - step
  return function()
    i = i + step
    if i <= stop then return i end
  end
end

for n in range(1, 5) do
  print(n)               -- 1, 2, 3, 4, 5
end

Higher-Order Functions

Functions as arguments and return values
-- Map
local function map(t, fn)
  local result = {}
  for i, v in ipairs(t) do
    result[i] = fn(v)
  end
  return result
end

local ports = { 22, 80, 443 }
local labels = map(ports, function(p)
  return string.format("%d/tcp", p)
end)
-- { "22/tcp", "80/tcp", "443/tcp" }

-- Compose
local function compose(f, g)
  return function(...)
    return f(g(...))
  end
end

local double = function(x) return x * 2 end
local add_one = function(x) return x + 1 end
local double_then_add = compose(add_one, double)
print(double_then_add(5))    -- 11

-- Memoize
local function memoize(fn)
  local cache = {}
  return function(arg)
    if cache[arg] == nil then
      cache[arg] = fn(arg)
    end
    return cache[arg]
  end
end

Method Syntax

Colon syntax and self
-- Dot syntax (explicit self)
local device = { hostname = "vault-01" }
function device.info(self)
  return self.hostname
end

-- Colon syntax (implicit self) -- preferred
function device:status()
  return self.hostname .. " is up"
end

-- Calling
print(device.info(device))   -- explicit
print(device:status())        -- implicit self (same as device.status(device))