๐ŸŒ™

A language tour

The Lightness of Lua

260KB. One data structure. Embeds in anything. The smallest language with the largest footprint you've never noticed.

scroll

01 โ€” The Embedded Language

Everywhere you haven't noticed

Lua is embedded in World of Warcraft, Roblox, Redis, Nginx, Wireshark, VLC, and thousands of games. Its entire runtime is 260 kilobytes. It was designed from the start to be hosted inside another application โ€” the perfect scripting companion.

"Lua means 'moon' in Portuguese. It is not an acronym. And it has always been written 'Lua', not 'LUA'."

โ€” Lua FAQ, Roberto Ierusalimschy
hello.lua
-- Lua syntax is clean and minimal
print("Hello, world!")

-- Variables are global by default โ€” use local
local name = "Lua"
local year = 1993

print(string.format("%s was born in %d", name, year))

-- The runtime is tiny โ€” 260KB for the entire interpreter
-- No dependencies, no standard library bloat
-- Just: tables, coroutines, closures, metatables, and C API

Lua's small footprint is not an accident โ€” it's the primary design goal. Every language feature was considered through the lens of: "does this pay its weight in the embedded use case?"


02 โ€” Tables

One data structure to rule them all

Lua has exactly one composite data structure: the table. It's an array. It's a hash map. It's a set. It's an object. It's a namespace. It's a module. The entire language is built on this one idea, and it's remarkably powerful.

tables.lua
-- A table as array (1-indexed!)
local fruits = {"apple", "banana", "cherry"}
print(fruits[1])  -- "apple" โ€” Lua arrays start at 1

-- A table as hash map
local config = {
    host    = "localhost",
    port    = 8080,
    debug   = true
}

-- A table as object
local point = { x = 3, y = 4 }
function point:length()
    return math.sqrt(self.x^2 + self.y^2)
end
print(point:length())  -- 5.0

The colon syntax in point:length() is syntactic sugar โ€” it's equivalent to point.length(point), passing the table as the first argument. Objects in Lua are just tables with a calling convention.


03 โ€” Metatables

Extend behaviour without inheritance

Metatables give tables special behaviour when you try to access missing keys, do arithmetic, or call them as functions. OOP, operator overloading, proxies โ€” all built from this one mechanism.

metatables.lua
local Vector = {}
Vector.__index = Vector

function Vector.new(x, y)
    return setmetatable({ x=x, y=y }, Vector)
end

-- __add is called when + is used on two vectors
function Vector:__add(other)
    return Vector.new(self.x + other.x, self.y + other.y)
end

-- __tostring controls print() output
function Vector:__tostring()
    return string.format("(%g, %g)", self.x, self.y)
end

local a = Vector.new(1, 2)
local b = Vector.new(3, 4)
print(tostring(a + b))  -- (4, 6)

__index, __add, __tostring โ€” metamethods are the hooks that let tables intercept and respond to language operations. Everything in Lua that looks like OOP is built from these hooks.


04 โ€” Coroutines

Cooperative multitasking without threads

Lua has native coroutines โ€” functions that can pause themselves and hand control back to the caller. No threads, no locks, no race conditions. Coroutines enabled async patterns in Lua long before they were fashionable in other languages.

coroutines.lua
-- A generator using coroutines
local function range(from, to)
    return coroutine.wrap(function()
        for i = from, to do
            coroutine.yield(i)
        end
    end)
end

for n in range(1, 5) do
    io.write(n .. " ")
end
-- 1 2 3 4 5

-- Producer-consumer without threads
local producer = coroutine.create(function()
    for i = 1, 3 do
        coroutine.yield("item_" .. i)
    end
end)

coroutine.wrap returns a plain function โ€” calling it resumes the coroutine and returns the yielded value. This pattern is Lua's equivalent of Python generators, introduced over a decade earlier.


05 โ€” Closures

Functions that remember

Lua has first-class functions and closures โ€” functions capture the variables of their enclosing scope. This is the foundation of Lua's module system, the OOP pattern, and most of its higher-order programming idioms.

closures.lua
-- A counter factory โ€” each call gets its own count
local function make_counter(start)
    local count = start
    return {
        inc  = function() count = count + 1 end,
        get  = function() return count end,
        reset = function() count = start end
    }
end

local c = make_counter(10)
c.inc(); c.inc()
print(c.get())  -- 12
c.reset()
print(c.get())  -- 10

Each call to make_counter creates a new upvalue โ€” a shared variable captured by all three returned functions. This is encapsulation in Lua: private state through closures, not classes.


06 โ€” The Whole Picture

Why Lua is enduring

๐ŸŽฎ

Game Scripting

World of Warcraft, Roblox, CryEngine, Defold โ€” if a game has a scripting layer, it's probably Lua.

โšก

LuaJIT

LuaJIT is one of the fastest dynamic language runtimes ever built. Competitive with compiled languages on numeric code.

๐Ÿ“ฆ

Zero Dependencies

The entire interpreter is a handful of C files. No external libraries, no build system โ€” just drop it in and compile.

๐Ÿ”ง

C API

The C API is excellent โ€” bidirectional, stack-based, and stable. Extending Lua from C is genuinely pleasant.

๐ŸŒ

OpenResty / Nginx

Nginx + LuaJIT runs some of the highest-traffic sites on the web. Lua scripting at the HTTP layer.

๐Ÿ“–

The Book

"Programming in Lua" by the language's creator is still one of the best programming language books ever written.