Table Reference vs Value Copy in Lua
The Error
local original = {x = 1, y = 2} local copy = original -- Seems like a copy, but isn't! copy.x = 5 print(original.x) -- Unexpectedly prints 5, not 1
Error Message You Might See:
Unexpected table modification: Changes to the 'copy' are affecting the original table
Quick Error Explanation
In Lua, when you assign a table to a new variable, you're creating a reference to the same table, not a copy. This is similar to pointers in C or references in Java. Any changes made through either variable will modify the same underlying data structure. This behavior often surprises developers coming from languages where assignment creates copies by default.
The Problem
One of the most common sources of bugs in Lua occurs when developers expect tables to be copied by value, but they are actually passed by reference. This can lead to unexpected modifications of data.
-- Bug Example local function modifyTable(t) t.value = 42 end local originalTable = {value = 10} local supposedCopy = originalTable -- This creates a reference, not a copy! modifyTable(supposedCopy) print(originalTable.value) -- Outputs: 42 (not 10 as might be expected)
Why It Happens
In Lua, tables are reference types. When you assign a table to a new variable or pass it as an argument, you're creating a new reference to the same table, not a copy of its contents.
How to Fix It
To create an actual copy of a table, you need to explicitly copy its contents:
-- Solution 1: Shallow copy local function shallowCopy(t) local copy = {} for k, v in pairs(t) do copy[k] = v end return copy end local originalTable = {value = 10} local actualCopy = shallowCopy(originalTable) modifyTable(actualCopy) print(originalTable.value) -- Outputs: 10 (original remains unchanged) print(actualCopy.value) -- Outputs: 42 (only the copy is modified)
For nested tables, you'll need a deep copy:
-- Solution 2: Deep copy local function deepCopy(t) if type(t) ~= 'table' then return t end local copy = {} for k, v in pairs(t) do copy[k] = type(v) == 'table' and deepCopy(v) or v end return copy end
Best Practices
- Always be explicit about whether you need a reference or a copy
- Use shallow copies for flat tables
- Use deep copies for nested structures
- Document functions that modify their table arguments
- Consider using immutable patterns for complex data structures
Common Pitfalls
- Forgetting that function arguments are references
- Not considering nested tables when copying
- Assuming assignment creates a copy
- Modifying shared table references in multiple places
Related Concepts
- Table metatables
- Garbage collection
- Memory management
- Function parameter passing