(Being this my first interaction in Stackoverflow I hope I am not breaking any rules by confirming @AlexanderMashin's answer (in the comments section) with a detailed explanation from DeepSeek)
@AlexanderMashin pointed me to the right direction. I asked DeepSeek (DeepThink R1):
"Explain me why in Lua when modifying a copy of a table, made in a non deep copy method, for example by declaring a `local table_copy = table_original`, the original table changes too? Why does this happen?"
DeepSeek's answer confirmed points 1) and 4) of @AlexanderMashin's answer in his comments:
"1) Lua tables are passed by reference. You need to clone a Lua table if you want to change the copy without assfecting the original. 4) is the ulimate purpose of your code to create a table based on a template, in which metacharacters are replaceb by vaues from anothe table?"
Here is my question to DeepSeek:
"Explain me why in Lua when modifying a copy of a table, made in a non deep copy method, for example by declaring a `local table_copy = table_original`, the original table changes too? Why does this happen?"
And it's answer was:
"In Lua, tables are reference types, not value types. When you assign a table to a new variable using local table_copy = table_original
, you are not creating a new table. Instead, you are creating a new reference to the same underlying table data in memory. This means:
Tables are references:
When you write table_copy = table_original
, both table_copy
and table_original
point to the same table in memory.
Changes made via either variable will affect the same underlying data.
local original = {value = 10}
local copy = original -- Both variables reference the same table
copy.value = 20 -- Modify the shared table
print(original.value) -- Output: 20 (original is changed!)
Shallow copies are not enough for nested tables:
Even if you manually copy keys with a loop (a "shallow copy"), nested tables inside the original table will still be referenced, not cloned:
function shallowCopy(original)
local copy = {}
for k, v in pairs(original) do
copy[k] = v -- Copies primitive values (numbers, strings) but references nested tables
end
return copy
end
local original = {nested = {value = 10}}
local copy = shallowCopy(original)
copy.nested.value = 20 -- Modifies the original's nested table
print(original.nested.value) -- Output: 20
--------------------------------
A deep copy recursively clones all nested tables, ensuring no shared references:
function deepCopy(original)
local copy = {}
for k, v in pairs(original) do
if type(v) == "table" then
copy[k] = deepCopy(v) -- Recursively clone nested tables
else
copy[k] = v -- Copy primitives directly
end
end
return copy
end
local original = {nested = {value = 10}}
local copy = deepCopy(original)
copy.nested.value = 20
print(original.nested.value) -- Output: 10 (original remains unchanged)
Assignment (=
) does not clone tables; it creates a new reference to the same data.
Shallow copies copy top-level keys, but nested tables remain shared references.
Deep copies are required to fully clone all nested structures.
This behavior is intentional in Lua to avoid unnecessary memory duplication, but it requires awareness when working with mutable data."
Conclusion:
For me as a beginner this is a revelation, now I will act accordingly to this behavior of Lua tables that had me perplexed. "This behavior is intentional in Lua to avoid unnecessary memory duplication, but it requires awareness when working with mutable data." Thanks to @AlexanderMashin !