Lua's 21 Keywords and One Data Structure: A JS Developer's Tour
Lua is embedded inside Neovim, Redis, World of Warcraft, OpenResty, and Roblox. A developer who configures any of those tools is already surrounded by Lua code, and the language's table-and-metatable model is the key to reading and writing it fluently.
Lua has only 21 keywords and one composite data structure: the table. Arrays start at 1, not 0; `nil` is the sole null-ish value and doubles as a deletion mechanism; and `0` and `""` are truthy, which trips up developers coming from JavaScript. Functions return multiple values directly, and proper tail calls keep deep recursion safe.
Metatables are the language's metaprogramming backbone. `__index` provides prototype-style lookup for missing keys, forming the basis of class-like OOP without a `class` keyword. Other metamethods like `__add` and `__eq` let tables participate in arithmetic and comparison operators—a capability that remains an advanced Proxy trick in JavaScript but is everyday infrastructure here.
A full Dijkstra shortest-path implementation closes the tutorial, using nested tables as an adjacency list, `pairs` for iteration, and truthy/falsy checks in place of a visited set. The same program in JavaScript would spread across `Map`, `Set`, and plain objects; Lua collapses it all into tables.
Lua's 1-based indexing is a deliberate design choice rooted in the Fortran background of its first users, not an oversight—and the language's creator has publicly argued that 0-based indexing spread mainly through C's pointer arithmetic, a rationale that doesn't apply to higher-level languages.
The table-as-universal-data-structure design means Lua programs avoid the conceptual overhead of choosing among Array, Object, Map, and Set. A single mental model covers all of them, at the cost of losing the performance guarantees those specialized types provide in other languages.
Metatables are not an advanced feature bolted on later; they are the substrate on which Lua's own object system and operator semantics are built. This inverts the relationship seen in JavaScript, where Proxy is a power tool most developers rarely touch.
Lua's `pcall`-based error handling and runtime `require` reflect a language designed to be embedded: syntax is kept minimal, and control structures that might conflict with a host program's own error model are deferred to library functions.