Skip to content

Lua Beginners Guide

Lua is a lightweight, high-level programming language designed for embedded use in applications. This guide covers the essential concepts you need to know to write Lua scripts in CoCoCo.

Variables and Data Types

Basic Variables

lua
-- Variables don't need type declarations
local name = "John Doe"           -- String
local age = 30                     -- Number (integer)
local price = 99.99                -- Number (float)
local is_active = true             -- Boolean
local nothing = nil                -- Nil (absence of value)

-- Local vs global variables
local x = 10        -- Local variable (recommended)
y = 20              -- Global variable (avoid when possible)

-- Multiple assignment
local a, b, c = 1, 2, 3
local x, y = y, x   -- Swap values

Strings

lua
-- String creation
local single = 'Single quotes'
local double = "Double quotes"
local multiline = [[
    This is a
    multiline string
]]

-- String concatenation
local first = "Hello"
local last = "World"
local message = first .. " " .. last    -- "Hello World"

-- String functions
local text = "Hello World"
print(string.len(text))                  -- 11
print(string.upper(text))                -- "HELLO WORLD"
print(string.lower(text))                -- "hello world"
print(string.sub(text, 1, 5))           -- "Hello"
print(string.find(text, "World"))       -- 7, 11
print(string.gsub(text, "World", "Lua")) -- "Hello Lua"

-- String formatting
local formatted = string.format("Name: %s, Age: %d, Price: $%.2f",
    "John", 30, 99.99)
-- "Name: John, Age: 30, Price: $99.99"

Numbers

lua
-- All numbers are floating point
local integer = 42
local float = 3.14159
local scientific = 1.5e10
local hex = 0xff        -- 255 in decimal

-- Arithmetic operations
local sum = 10 + 5      -- 15
local diff = 10 - 5     -- 5
local product = 10 * 5  -- 50
local quotient = 10 / 5 -- 2
local remainder = 10 % 3 -- 1
local power = 2 ^ 3     -- 8

-- Math functions
print(math.floor(3.7))   -- 3
print(math.ceil(3.2))    -- 4
print(math.abs(-5))      -- 5
print(math.sqrt(16))     -- 4
print(math.random())     -- Random between 0 and 1
print(math.random(1, 10)) -- Random integer between 1 and 10
print(math.min(3, 1, 5)) -- 1
print(math.max(3, 1, 5)) -- 5

Tables (Arrays and Dictionaries)

Tables are Lua's only data structure and serve as arrays, dictionaries, and objects.

Arrays (Sequential Tables)

lua
-- Creating arrays (1-indexed!)
local fruits = {"apple", "banana", "orange"}
local numbers = {10, 20, 30, 40, 50}

-- Accessing elements (starts at 1, not 0!)
print(fruits[1])     -- "apple"
print(fruits[2])     -- "banana"

-- Adding elements
fruits[4] = "grape"
table.insert(fruits, "mango")     -- Adds to end
table.insert(fruits, 2, "pear")   -- Insert at position 2

-- Removing elements
table.remove(fruits)      -- Removes last element
table.remove(fruits, 2)   -- Removes element at position 2

-- Array length
print(#fruits)           -- Number of elements

-- Iterating arrays
for i = 1, #fruits do
    print(i, fruits[i])
end

-- Using ipairs for iteration
for index, value in ipairs(fruits) do
    print(index, value)
end

Dictionaries (Associative Tables)

lua
-- Creating dictionaries
local person = {
    name = "John Doe",
    age = 30,
    email = "john@example.com"
}

-- Alternative syntax
local product = {}
product.name = "Widget"
product.price = 99.99
product["in_stock"] = true

-- Accessing values
print(person.name)         -- "John Doe"
print(person["age"])       -- 30

-- Nested tables
local company = {
    name = "Acme Corp",
    address = {
        street = "123 Main St",
        city = "Springfield",
        zip = "12345"
    },
    employees = {
        {name = "Alice", role = "Manager"},
        {name = "Bob", role = "Developer"}
    }
}

print(company.address.city)           -- "Springfield"
print(company.employees[1].name)      -- "Alice"

-- Iterating dictionaries
for key, value in pairs(person) do
    print(key .. ": " .. tostring(value))
end

-- Checking if key exists
if person.phone then
    print("Has phone")
else
    print("No phone")
end

Control Flow

If Statements

lua
local age = 18

if age >= 18 then
    print("Adult")
else
    print("Minor")
end

-- Multiple conditions
local score = 85

if score >= 90 then
    print("A")
elseif score >= 80 then
    print("B")
elseif score >= 70 then
    print("C")
else
    print("F")
end

-- Logical operators
local x = 10
local y = 20

if x > 5 and y < 30 then
    print("Both conditions true")
end

if x > 100 or y > 15 then
    print("At least one condition true")
end

if not (x == y) then
    print("x is not equal to y")
end

-- Ternary-like operation (using and/or)
local status = age >= 18 and "adult" or "minor"

Loops

lua
-- While loop
local count = 1
while count <= 5 do
    print("Count: " .. count)
    count = count + 1
end

-- Repeat-until loop (executes at least once)
local num = 0
repeat
    num = num + 1
    print("Number: " .. num)
until num >= 5

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

-- For loop with step
for i = 0, 100, 10 do    -- 0, 10, 20, ..., 100
    print(i)
end

-- For loop (counting down)
for i = 10, 1, -1 do
    print(i)
end

-- Break and continue (Lua doesn't have continue)
for i = 1, 10 do
    if i == 5 then
        break  -- Exit loop
    end
    print(i)
end

-- Simulating continue with goto (Lua 5.2+)
for i = 1, 10 do
    if i % 2 == 0 then
        goto continue
    end
    print(i)  -- Only prints odd numbers
    ::continue::
end

Functions

Basic Functions

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

-- Alternative syntax
local greet = function(name)
    return "Hello, " .. name
end

-- Calling functions
local message = greet("World")
print(message)  -- "Hello, World"

-- Multiple parameters
function add(a, b)
    return a + b
end

local sum = add(5, 3)  -- 8

-- Multiple return values
function divide(a, b)
    local quotient = math.floor(a / b)
    local remainder = a % b
    return quotient, remainder
end

local q, r = divide(10, 3)
print("Quotient: " .. q .. ", Remainder: " .. r)
-- "Quotient: 3, Remainder: 1"

-- Variable arguments
function sum_all(...)
    local args = {...}
    local total = 0
    for _, v in ipairs(args) do
        total = total + v
    end
    return total
end

print(sum_all(1, 2, 3, 4, 5))  -- 15

-- Default parameters (using or)
function greet_with_default(name)
    name = name or "Guest"
    return "Hello, " .. name
end

print(greet_with_default())        -- "Hello, Guest"
print(greet_with_default("John"))  -- "Hello, John"

Anonymous Functions and Closures

lua
-- Anonymous function
local multiply = function(x, y)
    return x * y
end

-- Functions as arguments
local function apply_operation(a, b, operation)
    return operation(a, b)
end

local result = apply_operation(10, 5, function(x, y)
    return x - y
end)
print(result)  -- 5

-- Closures (functions that capture variables)
function create_counter()
    local count = 0
    return function()
        count = count + 1
        return count
    end
end

local counter = create_counter()
print(counter())  -- 1
print(counter())  -- 2
print(counter())  -- 3

-- Higher-order functions
function map(array, func)
    local result = {}
    for i, v in ipairs(array) do
        result[i] = func(v)
    end
    return result
end

local numbers = {1, 2, 3, 4, 5}
local doubled = map(numbers, function(x) return x * 2 end)
-- doubled = {2, 4, 6, 8, 10}

Error Handling

lua
-- Protected calls with pcall
function risky_operation(x)
    if x < 0 then
        error("Cannot process negative numbers")
    end
    return math.sqrt(x)
end

-- Using pcall to catch errors
local success, result = pcall(risky_operation, -5)
if success then
    print("Result: " .. result)
else
    print("Error: " .. result)  -- result contains error message
end

-- Custom error handling
function safe_divide(a, b)
    if b == 0 then
        return nil, "Division by zero"
    end
    return a / b, nil
end

local result, err = safe_divide(10, 0)
if err then
    print("Error: " .. err)
else
    print("Result: " .. result)
end

-- Assert for debugging
local function process_positive(n)
    assert(n > 0, "Number must be positive")
    return n * 2
end

-- Type checking
function process_string(s)
    if type(s) ~= "string" then
        error("Expected string, got " .. type(s))
    end
    return string.upper(s)
end

Common Patterns

Object-Oriented Programming

lua
-- Simple object creation
function create_person(name, age)
    local person = {
        name = name,
        age = age
    }

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

    function person:have_birthday()
        self.age = self.age + 1
    end

    return person
end

local john = create_person("John", 30)
print(john:greet())        -- "Hello, I'm John"
john:have_birthday()
print(john.age)            -- 31

-- Metatables for OOP
local Person = {}
Person.__index = Person

function Person.new(name, age)
    local self = setmetatable({}, Person)
    self.name = name
    self.age = age
    return self
end

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

local jane = Person.new("Jane", 25)
print(jane:greet())

Module Pattern

lua
-- Creating a module
local MyModule = {}

local private_var = "hidden"

local function private_function()
    return "private"
end

function MyModule.public_function()
    return "public: " .. private_function()
end

MyModule.public_var = "visible"

return MyModule

Useful Tips

  1. Table indices start at 1, not 0 like most languages
  2. Use local for all variables to avoid polluting global scope
  3. Functions are first-class values - they can be stored in variables and passed around
  4. Only nil and false are falsy - 0 and empty strings are truthy!
  5. Use pairs() for all tables, ipairs() only for sequential arrays
  6. String concatenation uses .. not +
  7. Comments use -- for single line and --[[ ]] for multiline

Connect. Combine. Collaborate.
The pioneering open integration platform, dedicated to transforming connectivity in the printing industry.