Metatables: a vector type with operators
Metamethods give a table arithmetic, equality and a readable tostring. print converts each argument with tostring, so the vector is printed through __tostring. Expected output: (3, 4), 5.0 and true, separated by tabs. The 5.0 shows Lua 5.3's separate float subtype.
local Vector = {}
Vector.__index = Vector
function Vector.new(x, y)
return setmetatable({ x = x, y = y }, Vector)
end
function Vector.__add(a, b) return Vector.new(a.x + b.x, a.y + b.y) end
function Vector.__eq(a, b) return a.x == b.x and a.y == b.y end
function Vector:__tostring() return ("(%g, %g)"):format(self.x, self.y) end
function Vector:length() return math.sqrt(self.x ^ 2 + self.y ^ 2) end
local v = Vector.new(3, 4) + Vector.new(0, 0)
print(v, v:length(), v == Vector.new(3, 4))
Coroutines as generators
coroutine.wrap turns a function that yields into an iterator for a generic for loop. This one produces every third number from 1 to 10, and the loop collects their squares. Expected output: 1, 16, 49, 100.
local function range(n, step)
return coroutine.wrap(function()
for i = 1, n, step or 1 do coroutine.yield(i) end
end)
end
local squares = {}
for i in range(10, 3) do
squares[#squares + 1] = i * i
end
print(table.concat(squares, ", "))
Integers, floor division, bitwise operators and patterns
Lua 5.3 features in a few lines: // floor division, math.type, bitwise operators and gmatch captures. math.maxinteger prints 2147483647 because Fengari uses 32-bit integers, where the C implementation prints 9223372036854775807. The loop splits a log line into date, level and message.
print(7 // 2, 7 / 2, 7 % 3)
print(math.type(1), math.type(1.0), math.maxinteger)
print(0xF0 | 0x0F, 1 << 8, ~0)
local log = "2026-09-14 ERROR disk full; 2026-09-14 WARN retrying"
for date, level, msg in log:gmatch("(%d+%-%d+%-%d+) (%u+) ([^;]+)") do
print(date, level, msg)
end