Overriding table when editing cloned version?

Hello! This is my first post so apologies in advance for any confusion. I was editing a table of mine when I realized that the edits to the cloned table applied to the table that was cloned! Is this a bug or a function within table data? The cloned table is for a datastore, and is cloned so I do not have to edit the same table twice for saving and loading data. Please let me know if I am approaching this wrong.

local tableTest = {"Hello!", ["Phrases"] = {["Good Riddance!"] = false}}
local cloneTable = table.clone(tableTest)

cloneTable["Phrases"]["What in the World?"] = true

print(cloneTable)
print(tableTest)

-- both tables are affected!

When you create a copy of a table, both the original and copied table end up connected. If you make changes to one, it affects the other, basically like twins.

As a solution, you need to create a copy of the table that is independent so it doesn’t affect the other

View code
function cloneTable(original)
    local copy = {}

    for key, value in pairs(original) do
        if type(value) == "table" then
            copy[key] = cloneTable(value)
        else
            copy[key] = value
        end
    end
    return copy
end

local tableTest = {"Hello!", Phrases = {["Good Riddance!"] = false}}
local cloneTable = cloneTable(tableTest)

cloneTable.Phrases["What in the World?"] = true

print("cloneTable:")
for k, v in pairs(cloneTable) do
    print(k, v)
end

print("tableTest:")
for k, v in pairs(tableTest) do
    print(k, v)
end
1 Like

Oh! I did not that they were connected like that. Thanks for the assistance :slight_smile:

1 Like

The explanation in the solution is misleading, the original and copied table are not “connected” when you copy them with table.clone, only their sub-tables are. Using table.clone creates a shallow copy of the table, where only the first “layer” of the table is copied, while any sub-tables in the main table are left uncopied so it retains a reference to the original sub-tables.

For instance, simply calling table.clone on a table that looks like this:

local Table = {
    SubTable1 = {
        SubSubTable1 = {}
    },
    SubTable2 = {
        SubSubTable2 = {}
    }
}

Will create a new copy of table “Table” in memory, while its sub-tables “SubTable1”, “SubSubTable1”, “SubTable2”, “SubSubTable2” will still point to the old tables from the original table “Table”.

You can test this by directly comparing the tables with the equality operator (==).

local Table = {
	SubTable = {
		SubSubTable = {}
	}
}

local ClonedTable = table.clone(Table)

print(ClonedTable == Table) --> false
print(ClonedTable.SubTable == Table.SubTable) --> true
print(ClonedTable.SubSubTable == Table.SubSubTable) --> true

This means that editing ClonedTable.SubTable will also alter Table.SubTable, however, editing any values in ClonedTable itself will not affect any values in Table.

local Table = {
	Key = "Value",
	SubTable = {
		Key2 = "Value2"
	}
}

local ClonedTable = table.clone(Table)

ClonedTable.Key = "NewValue"
print(ClonedTable.Key) --> "NewValue"
print(Table.Key) --> "Value"

ClonedTable.SubTable.Key2 = "NewValue2"
print(ClonedTable.SubTable.Key2) --> "NewValue2"
print(Table.SubTable.Key2) --> "NewValue2" (!!!)

Though, the code in the solution is correct. The cloneTable function deep-copies the table and all of its sub-tables (by performing a recursive shallow copy).

7 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.