Lua - Variables & Constants
Overview
Estimated time: 20–25 minutes
Variables are containers for storing data values in Lua. This tutorial covers variable declaration, scoping rules, constants, and best practices for variable naming and usage.
Learning Objectives
- Understand variable declaration in Lua
- Master the difference between local and global variables
- Learn about variable scoping rules
- Implement constants and read-only values
- Apply proper naming conventions
Prerequisites
- Understanding of Lua data types
- Basic knowledge of Lua syntax
Variable Declaration
In Lua, variables don't need explicit type declarations. You simply assign a value:
-- Basic variable assignment
name = "Alice"
age = 25
height = 5.7
is_student = true
print("Name:", name)
print("Age:", age)
print("Height:", height)
print("Student:", is_student)
Expected Output:
Name: Alice
Age: 25
Height: 5.7
Student: true
Local vs Global Variables
Global Variables
Variables declared without local
are global by default:
-- Global variables (avoid when possible)
global_counter = 0
user_name = "John"
function increment_counter()
global_counter = global_counter + 1
end
increment_counter()
print("Global counter:", global_counter)
print("User name:", user_name)
Expected Output:
Global counter: 1
User name: John
Local Variables (Recommended)
Always prefer local variables for better performance and code organization:
-- Local variables (recommended)
local counter = 0
local name = "Alice"
local items = {"apple", "banana", "orange"}
local function process_items()
local total = 0
for i, item in ipairs(items) do
total = total + 1
print("Item " .. i .. ":", item)
end
return total
end
local item_count = process_items()
print("Total items:", item_count)
Expected Output:
Item 1: apple
Item 2: banana
Item 3: orange
Total items: 3
Variable Scoping
Block Scope
Local variables are limited to their containing block:
local x = 10
print("Outer x:", x)
do
local x = 20 -- Different variable
print("Inner x:", x)
local y = 30 -- Only exists in this block
print("Inner y:", y)
end
print("Outer x again:", x)
-- print("Outer y:", y) -- Error: y doesn't exist here
Expected Output:
Outer x: 10
Inner x: 20
Inner y: 30
Outer x again: 10
Function Scope
Variables declared in functions are local to that function:
local function calculate_area(length, width)
local area = length * width -- Local to this function
local perimeter = 2 * (length + width) -- Also local
print("Calculating area...")
return area, perimeter
end
local rectangle_area, rectangle_perimeter = calculate_area(5, 3)
print("Area:", rectangle_area)
print("Perimeter:", rectangle_perimeter)
-- area and perimeter don't exist outside the function
Expected Output:
Calculating area...
Area: 15
Perimeter: 16
Multiple Assignment
Lua supports multiple assignment in a single statement:
-- Multiple assignment
local a, b, c = 1, 2, 3
print("a, b, c:", a, b, c)
-- Swapping variables
local x, y = 10, 20
print("Before swap - x:", x, "y:", y)
x, y = y, x
print("After swap - x:", x, "y:", y)
-- Unequal assignments
local p, q, r = 100, 200 -- r will be nil
print("p, q, r:", p, q, r)
local s, t = 1, 2, 3, 4 -- Extra values ignored
print("s, t:", s, t)
Expected Output:
a, b, c: 1 2 3
Before swap - x: 10 y: 20
After swap - x: 20 y: 10
p, q, r: 100 200 nil
s, t: 1 2
Constants in Lua
Lua doesn't have built-in constants, but we can simulate them:
Convention-based Constants
-- Convention: use ALL_CAPS for constants
local PI = 3.14159265359
local MAX_USERS = 1000
local DEFAULT_NAME = "Anonymous"
local VERSION = "1.0.0"
print("Pi:", PI)
print("Max users:", MAX_USERS)
print("Default name:", DEFAULT_NAME)
print("Version:", VERSION)
-- Grouped constants
local CONFIG = {
MAX_RETRIES = 3,
TIMEOUT = 30,
DEBUG_MODE = true
}
print("Max retries:", CONFIG.MAX_RETRIES)
print("Timeout:", CONFIG.TIMEOUT)
Expected Output:
Pi: 3.14159265359
Max users: 1000
Default name: Anonymous
Version: 1.0.0
Max retries: 3
Timeout: 30
Read-only Tables
Create read-only constants using metatables:
-- Read-only constants using metatables
local function make_readonly(table)
return setmetatable({}, {
__index = table,
__newindex = function(t, key, value)
error("Attempt to modify read-only table")
end
})
end
local CONSTANTS = make_readonly({
PI = 3.14159,
E = 2.71828,
GRAVITY = 9.81
})
print("Constants PI:", CONSTANTS.PI)
print("Constants E:", CONSTANTS.E)
-- This would cause an error:
-- CONSTANTS.PI = 3.14 -- Error: Attempt to modify read-only table
Expected Output:
Constants PI: 3.14159
Constants E: 2.71828
Variable Naming Conventions
Good Naming Practices
-- Good variable names (descriptive and clear)
local user_name = "Alice"
local total_score = 1250
local is_game_over = false
local player_position = {x = 10, y = 20}
local max_health_points = 100
-- Function names should be verbs
local function calculate_distance(x1, y1, x2, y2)
return math.sqrt((x2 - x1)^2 + (y2 - y1)^2)
end
-- Constants in ALL_CAPS
local MAX_PLAYERS = 4
local DEFAULT_LIVES = 3
print("User:", user_name)
print("Score:", total_score)
print("Game over:", is_game_over)
Naming Conventions
- Variables:
snake_case
(recommended) orcamelCase
- Constants:
ALL_CAPS_WITH_UNDERSCORES
- Functions:
snake_case
with verb names - Private variables: Prefix with underscore
_private_var
Variable Initialization
Initialize variables properly to avoid nil values:
-- Good initialization practices
local counter = 0 -- Initialize numbers to 0
local message = "" -- Initialize strings to empty
local items = {} -- Initialize tables to empty table
local is_ready = false -- Initialize booleans to false/true
local user_data = nil -- Explicit nil when appropriate
-- Default values for function parameters
local function greet(name, greeting)
name = name or "Guest" -- Default name
greeting = greeting or "Hello" -- Default greeting
return greeting .. ", " .. name .. "!"
end
print(greet()) -- Uses both defaults
print(greet("Alice")) -- Uses default greeting
print(greet("Bob", "Hi")) -- Uses provided values
Expected Output:
Hello, Guest!
Hello, Alice!
Hi, Bob!
Practical Examples
Configuration Management
-- Application configuration
local APP_CONFIG = {
-- Database settings
DB_HOST = "localhost",
DB_PORT = 5432,
DB_NAME = "myapp",
-- Application settings
MAX_CONNECTIONS = 100,
TIMEOUT_SECONDS = 30,
DEBUG_ENABLED = true,
-- Feature flags
ENABLE_LOGGING = true,
ENABLE_CACHING = false
}
-- Using configuration
local function connect_database()
if APP_CONFIG.DEBUG_ENABLED then
print("Connecting to database...")
print("Host:", APP_CONFIG.DB_HOST)
print("Port:", APP_CONFIG.DB_PORT)
print("Database:", APP_CONFIG.DB_NAME)
end
-- Connection logic here
end
connect_database()
State Management
-- Game state management
local game_state = {
player_name = "",
current_level = 1,
score = 0,
lives = 3,
is_paused = false
}
local function update_score(points)
game_state.score = game_state.score + points
print("Score updated:", game_state.score)
end
local function lose_life()
game_state.lives = game_state.lives - 1
if game_state.lives <= 0 then
print("Game Over!")
else
print("Lives remaining:", game_state.lives)
end
end
-- Example usage
game_state.player_name = "Player1"
update_score(100)
update_score(50)
lose_life()
Expected Output:
Connecting to database...
Host: localhost
Port: 5432
Database: myapp
Score updated: 100
Score updated: 150
Lives remaining: 2
Common Pitfalls
- Global pollution: Always use
local
unless you specifically need a global variable - Typos in variable names: Lua creates new globals for typos instead of errors
- Uninitialized variables: Variables default to
nil
, which might not be what you want - Scope confusion: Remember that variables are only visible in their declaring scope
Checks for Understanding
- What's the difference between local and global variables?
- How do you create multiple variables in one statement?
- What happens to extra values in multiple assignment?
- What's the recommended naming convention for constants?
- How can you provide default values for variables?
Show answers
- Local variables are declared with
local
and have limited scope; global variables are accessible everywhere but should be avoided. - Use comma-separated assignment:
local a, b, c = 1, 2, 3
- Extra values are ignored; missing values become
nil
- ALL_CAPS_WITH_UNDERSCORES for constants
- Use the
or
operator:name = name or "default"
Next Steps
Now that you understand variables and scoping, you're ready to dive deeper into Lua's data types and learn how to work with different kinds of values effectively.