Lua

Essential Lua syntax, tables, functions, and scripting patterns.

languages
luascriptingembeddedgamedev

Hello World

-- Simple hello world
print("Hello, World!")

-- With variables
local name = "Alice"
print("Hello, " .. name .. "!")

-- Using string.format
local greeting = string.format("Hello, %s!", name)
print(greeting)

Variables

-- Variables are global by default
name = "Alice"              -- String
age = 30                    -- Number (no separate int/float types)
is_active = true            -- Boolean
empty = nil                 -- Nil (absence of value)

-- Local variables (recommended)
local x = 10                -- Block-scoped
local y, z = 20, 30         -- Multiple assignment

Data Types

-- Lua has 8 basic types
local str = "text"          -- string
local num = 42              -- number
local bool = true           -- boolean
local func = function() end -- function
local tbl = {}              -- table
local nothing = nil         -- nil
local thread = coroutine.create(function() end) -- thread
-- userdata (for C integration)

-- Type checking
print(type(str))            -- "string"
print(type(num))            -- "number"

Strings

-- String creation
local s1 = "single quotes"
local s2 = 'double quotes'
local s3 = [[multi-line
string]]

-- String concatenation
local greeting = "Hello, " .. name .. "!"

-- String methods
local text = "Lua Programming"
print(text:upper())         -- "LUA PROGRAMMING"
print(text:lower())         -- "lua programming"
print(text:sub(1, 3))       -- "Lua" (1-indexed!)
print(text:len())           -- 15
print(text:find("Pro"))     -- 5, 7 (start and end positions)

-- String formatting
local msg = string.format("User %s is %d years old", name, age)

Tables

-- Arrays (1-indexed!)
local fruits = {"apple", "banana", "cherry"}
print(fruits[1])            -- "apple" (NOT 0!)
table.insert(fruits, "date") -- Add to end
table.remove(fruits, 1)     -- Remove first element

-- Dictionaries (hash tables)
local person = {
    name = "Alice",
    age = 30,
    active = true
}
print(person.name)          -- "Alice"
print(person["age"])        -- 30

-- Mixed tables
local mixed = {
    "first",                -- [1] = "first"
    "second",               -- [2] = "second"
    key = "value",          -- key-value pair
    [10] = "tenth"          -- numeric key
}

-- Table iteration
for key, value in pairs(person) do
    print(key, value)       -- Iterate all key-value pairs
end

for i, fruit in ipairs(fruits) do
    print(i, fruit)         -- Iterate array part only
end

Functions

-- Function definition
function greet(name)
    return "Hello, " .. name .. "!"
end

-- Multiple return values
function minmax(a, b)
    if a < b then
        return a, b         -- Return multiple values
    else
        return b, a
    end
end
local min, max = minmax(5, 3) -- min=3, max=5

-- Anonymous functions
local square = function(x)
    return x * x
end

-- Default parameters (Lua 5.x workaround)
function greet_with_default(name)
    name = name or "Guest"  -- Default value
    return "Hello, " .. name
end

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

Control Flow

-- If statements
if age >= 18 then
    print("Adult")
elseif age >= 13 then
    print("Teenager")
else
    print("Child")
end

-- Ternary-like (using 'and'/'or')
local status = is_active and "Active" or "Inactive"

-- Comparison operators
-- ==  ~=  <  >  <=  >=
-- and  or  not

Loops

-- While loop
local i = 1
while i <= 5 do
    print(i)
    i = i + 1
end

-- Repeat-until (do-while equivalent)
local j = 1
repeat
    print(j)
    j = j + 1
until j > 5

-- For loop (numeric)
for i = 1, 10 do            -- 1 to 10 inclusive
    print(i)
end

for i = 10, 1, -1 do        -- 10 to 1, step -1
    print(i)
end

-- For loop (generic)
local colors = {"red", "green", "blue"}
for index, color in ipairs(colors) do
    print(index, color)
end

-- Break (no continue in Lua)
for i = 1, 10 do
    if i == 5 then
        break               -- Exit loop
    end
    print(i)
end

Metatables

-- Metatables enable operator overloading and OOP
local vector = {x = 1, y = 2}
local vector_mt = {
    __add = function(a, b)  -- Overload + operator
        return {x = a.x + b.x, y = a.y + b.y}
    end,
    __tostring = function(v) -- Overload tostring()
        return string.format("(%d, %d)", v.x, v.y)
    end
}
setmetatable(vector, vector_mt)

local v1 = {x = 1, y = 2}
local v2 = {x = 3, y = 4}
setmetatable(v1, vector_mt)
setmetatable(v2, vector_mt)
local v3 = v1 + v2          -- v3.x=4, v3.y=6

-- __index for property lookup
local prototype = {
    greet = function(self)
        return "Hello, " .. self.name
    end
}
local obj = {name = "Alice"}
setmetatable(obj, {__index = prototype})
print(obj:greet())          -- "Hello, Alice"

Modules

-- mymodule.lua
local M = {}                -- Module table

function M.add(a, b)
    return a + b
end

function M.subtract(a, b)
    return a - b
end

return M

-- Using the module
local mymodule = require("mymodule")
print(mymodule.add(5, 3))   -- 8

File I/O

-- Read entire file
local file = io.open("data.txt", "r")
if file then
    local content = file:read("*a") -- Read all
    file:close()
end

-- Read line by line
local file = io.open("data.txt", "r")
if file then
    for line in file:lines() do
        print(line)
    end
    file:close()
end

-- Write to file
local file = io.open("output.txt", "w")
if file then
    file:write("Hello, World!\n")
    file:close()
end

-- Append to file
local file = io.open("output.txt", "a")
if file then
    file:write("Appended line\n")
    file:close()
end

Error Handling

-- Protected call (pcall)
local success, result = pcall(function()
    return 10 / 0           -- Potential error
end)

if success then
    print("Result:", result)
else
    print("Error:", result)
end

-- Assert (throw error if condition fails)
local function divide(a, b)
    assert(b ~= 0, "Division by zero!")
    return a / b
end

-- Manual error throwing
if age < 0 then
    error("Age cannot be negative")
end

Coroutines

-- Coroutines for cooperative multitasking
local co = coroutine.create(function()
    for i = 1, 3 do
        print("Coroutine:", i)
        coroutine.yield()   -- Pause execution
    end
end)

coroutine.resume(co)        -- Coroutine: 1
coroutine.resume(co)        -- Coroutine: 2
coroutine.resume(co)        -- Coroutine: 3

-- Check status
print(coroutine.status(co)) -- "dead" (finished)

Common Idioms

-- Ternary operator
local result = condition and value_if_true or value_if_false

-- Safe table access
local value = table and table.key or default_value

-- Swapping variables
a, b = b, a

-- Table as set
local set = {apple = true, banana = true}
if set["apple"] then
    print("Apple is in set")
end

-- Class-like pattern
function Person:new(name, age)
    local obj = {name = name, age = age}
    setmetatable(obj, {__index = Person})
    return obj
end

function Person:greet()
    return "Hello, I'm " .. self.name
end

local alice = Person:new("Alice", 30)
print(alice:greet())        -- "Hello, I'm Alice"