Lua - Data Types

Overview

Estimated time: 25–30 minutes

Lua has eight basic data types. Understanding these types is fundamental to becoming proficient in Lua programming. This tutorial explores each type with practical examples and use cases.

Learning Objectives

  • Understand all eight Lua data types
  • Learn how to check variable types
  • Master type conversion techniques
  • Understand dynamic typing in Lua
  • Apply appropriate types for different scenarios

Prerequisites

  • Basic Lua syntax knowledge
  • Understanding of variables and functions

Lua's Eight Data Types

Lua has exactly eight data types:

  1. nil - represents absence of value
  2. boolean - true or false
  3. number - integers and floating-point numbers
  4. string - text sequences
  5. table - associative arrays
  6. function - executable code blocks
  7. userdata - C data in Lua
  8. thread - coroutines

Checking Types

Use the type() function to check a variable's type:

local a = nil
local b = true
local c = 42
local d = "hello"
local e = {}
local f = function() end

print("Type of a:", type(a))  -- nil
print("Type of b:", type(b))  -- boolean
print("Type of c:", type(c))  -- number
print("Type of d:", type(d))  -- string
print("Type of e:", type(e))  -- table
print("Type of f:", type(f))  -- function

Expected Output:

Type of a:	nil
Type of b:	boolean
Type of c:	number
Type of d:	string
Type of e:	table
Type of f:	function

1. Nil Type

The nil type represents the absence of a value:

local unassigned_var  -- defaults to nil
local explicit_nil = nil

print("Unassigned:", unassigned_var)
print("Explicit nil:", explicit_nil)
print("Type:", type(unassigned_var))

-- Nil is falsy in boolean context
if unassigned_var then
    print("This won't print")
else
    print("nil is falsy")
end

-- Removing table elements
local fruits = {apple = "red", banana = "yellow"}
fruits.apple = nil  -- Remove the apple entry
print("Apple:", fruits.apple)  -- prints nil

Expected Output:

Unassigned:	nil
Explicit nil:	nil
Type:	nil
nil is falsy
Apple:	nil

2. Boolean Type

Booleans represent truth values:

local is_true = true
local is_false = false

print("True value:", is_true)
print("False value:", is_false)

-- Boolean operations
print("NOT true:", not is_true)
print("True AND false:", is_true and is_false)
print("True OR false:", is_true or is_false)

-- Truthiness in Lua: only nil and false are falsy
local values = {true, false, nil, 0, "", "hello", {}}
for i, value in ipairs(values) do
    if value then
        print("Value", i, "is truthy:", value)
    else
        print("Value", i, "is falsy:", value)
    end
end

Expected Output:

True value:	true
False value:	false
NOT true:	false
True AND false:	false
True OR false:	true
Value	1	is truthy:	true
Value	2	is falsy:	false
Value	3	is falsy:	nil

3. Number Type

Lua has a single number type that represents both integers and floats:

-- Different number formats
local integer = 42
local float = 3.14159
local scientific = 1.23e10
local hexadecimal = 0xFF
local binary = 0b1010  -- Lua 5.4+ only

print("Integer:", integer, type(integer))
print("Float:", float, type(float))
print("Scientific:", scientific, type(scientific))
print("Hexadecimal:", hexadecimal, type(hexadecimal))

-- Number operations
print("Addition:", 10 + 5)
print("Subtraction:", 10 - 5)
print("Multiplication:", 10 * 5)
print("Division:", 10 / 3)
print("Floor division:", 10 // 3)
print("Modulo:", 10 % 3)
print("Exponentiation:", 2 ^ 3)

-- Checking if a number is an integer
print("Is 42 an integer?", math.type(42) == "integer")
print("Is 3.14 an integer?", math.type(3.14) == "integer")

Expected Output:

Integer:	42	number
Float:	3.14159	number
Scientific:	12300000000	number
Hexadecimal:	255	number
Addition:	15
Subtraction:	5
Multiplication:	50
Division:	3.3333333333333
Floor division:	3
Modulo:	1
Exponentiation:	8
Is 42 an integer?	true
Is 3.14 an integer?	false

4. String Type

Strings represent sequences of characters:

-- Different string literals
local single_quote = 'Hello, World!'
local double_quote = "Hello, World!"
local long_string = [[
This is a multi-line string.
It can span multiple lines.
Useful for long text.]]

print("Single quotes:", single_quote)
print("Double quotes:", double_quote)
print("Long string:", long_string)

-- String operations
local str1 = "Hello"
local str2 = "World"
local combined = str1 .. ", " .. str2 .. "!"
print("Concatenation:", combined)
print("Length:", #combined)

-- String with escape sequences
local escaped = "Line 1\nLine 2\tTabbed\n\"Quoted\""
print("Escaped string:")
print(escaped)

-- Automatic conversion
local num_str = "The answer is " .. 42
print("Number to string:", num_str)
print("Type:", type(num_str))

Expected Output:

Single quotes:	Hello, World!
Double quotes:	Hello, World!
Long string:	
This is a multi-line string.
It can span multiple lines.
Useful for long text.
Concatenation:	Hello, World!
Length:	13
Escaped string:
Line 1
Line 2	Tabbed
"Quoted"
Number to string:	The answer is 42
Type:	string

5. Table Type

Tables are Lua's only data structure, serving as arrays, objects, and more:

-- Array-like table (1-indexed)
local fruits = {"apple", "banana", "orange"}
print("First fruit:", fruits[1])
print("Table length:", #fruits)

-- Dictionary-like table
local person = {
    name = "Alice",
    age = 30,
    city = "New York"
}
print("Person name:", person.name)
print("Person age:", person["age"])

-- Mixed table
local mixed = {
    "first element",  -- index 1
    "second element", -- index 2
    key1 = "value1",
    key2 = "value2"
}
print("Mixed[1]:", mixed[1])
print("Mixed key1:", mixed.key1)

-- Empty table
local empty = {}
print("Empty table type:", type(empty))
print("Empty table length:", #empty)

Expected Output:

First fruit:	apple
Table length:	3
Person name:	Alice
Person age:	30
Mixed[1]:	first element
Mixed key1:	value1
Empty table type:	table
Empty table length:	0

6. Function Type

Functions are first-class values in Lua:

-- Regular function
local function greet(name)
    return "Hello, " .. name .. "!"
end

-- Anonymous function
local multiply = function(a, b)
    return a * b
end

-- Function as table value
local math_ops = {
    add = function(a, b) return a + b end,
    subtract = function(a, b) return a - b end
}

print("Function type:", type(greet))
print("Greet function:", greet("Lua"))
print("Multiply function:", multiply(4, 5))
print("Math add:", math_ops.add(10, 5))

-- Passing functions as arguments
local function apply_operation(func, a, b)
    return func(a, b)
end

print("Apply multiply:", apply_operation(multiply, 3, 7))

Expected Output:

Function type:	function
Greet function:	Hello, Lua!
Multiply function:	20
Math add:	15
Apply multiply:	21

7. Userdata Type

Userdata represents C data in Lua (less common in pure Lua):

-- File handles are userdata
local file = io.open("test.txt", "w")
if file then
    print("File type:", type(file))
    file:write("Hello from Lua!")
    file:close()
else
    print("Could not open file")
end

-- Some other examples of userdata:
-- - File handles from io.open()
-- - Pattern objects from regex libraries
-- - Custom C objects exposed to Lua

8. Thread Type

Threads represent coroutines in Lua:

-- Create a coroutine
local function simple_coroutine()
    print("Coroutine: Starting")
    coroutine.yield("First yield")
    print("Coroutine: After first yield")
    coroutine.yield("Second yield")
    print("Coroutine: Ending")
    return "Done"
end

local co = coroutine.create(simple_coroutine)
print("Coroutine type:", type(co))
print("Coroutine status:", coroutine.status(co))

-- Resume the coroutine
local success, value = coroutine.resume(co)
print("First resume:", success, value)

local success, value = coroutine.resume(co)
print("Second resume:", success, value)

local success, value = coroutine.resume(co)
print("Final resume:", success, value)

Expected Output:

Coroutine type:	thread
Coroutine status:	suspended
Coroutine: Starting
First resume:	true	First yield
Coroutine: After first yield
Second resume:	true	Second yield
Coroutine: Ending
Final resume:	true	Done

Type Conversions

Lua provides functions for type conversions:

-- String to number
local str_num = "123"
local num = tonumber(str_num)
print("String to number:", str_num, "->", num, type(num))

-- Invalid conversion returns nil
local invalid = tonumber("abc")
print("Invalid conversion:", invalid)

-- Number to string (automatic in many contexts)
local num_to_str = tostring(42)
print("Number to string:", 42, "->", num_to_str, type(num_to_str))

-- Boolean to string
local bool_to_str = tostring(true)
print("Boolean to string:", true, "->", bool_to_str, type(bool_to_str))

-- Automatic conversions in operations
print("Auto conversion in concat:", "Number: " .. 42)
print("Auto conversion in comparison:", "10" == 10)  -- false (different types)
print("Auto conversion in arithmetic:", "10" + 5)     -- 15

Expected Output:

String to number:	123	->	123	number
Invalid conversion:	nil
Number to string:	42	->	42	string
Boolean to string:	true	->	true	string
Auto conversion in concat:	Number: 42
Auto conversion in comparison:	false
Auto conversion in arithmetic:	15

Common Pitfalls

  • Type confusion: Remember that "10" == 10 is false (different types)
  • Nil vs false: Only nil and false are falsy in Lua
  • Number precision: Floating-point numbers have limited precision
  • Table indexing: Lua arrays are 1-indexed, not 0-indexed

Checks for Understanding

  1. How many data types does Lua have?
  2. What function checks the type of a variable?
  3. Which values are considered falsy in Lua?
  4. What's the difference between 10 and "10"?
  5. What data structure does Lua use for arrays and objects?
Show answers
  1. Eight data types: nil, boolean, number, string, table, function, userdata, thread
  2. type() function returns the type as a string
  3. Only nil and false are falsy; everything else is truthy
  4. 10 is a number, "10" is a string - they are different types
  5. Tables - they serve as arrays, objects, dictionaries, and more

Next Steps

Now that you understand Lua's type system, you're ready to explore operators and learn how to manipulate these different data types effectively.