TrashMachine
TrashMachine

Reputation: 69

Copying a tables values in Lua is changing the originals value

I want to copy a simple table however whenever I change the copied table it changes the original table too and it's very bizarre

function tablelength(T)
  local count = 0
    for _ in pairs(T) do count = count + 1 end
  return count
end

board = {}
print("board: "..tablelength(board))

newBoard = board
newBoard[tablelength(newBoard) + 1] = 1
print("board: "..tablelength(board))
newBoard[tablelength(newBoard) + 1] = 1
print("board: "..tablelength(board))

Output:

board: 0
board: 1
board: 2

Upvotes: 1

Views: 750

Answers (1)

Alexander Mashin
Alexander Mashin

Reputation: 4602

newBoard = board only created a new reference newBoard, second after board, to the same table, which was creared by {}.

You need to deep copy a table, if you want a new one.

Something like this:

local function deep_copy( tbl )
    local copy = {}
    for key, value in pairs( tbl ) do
        if type( value ) ~= 'table' then
            copy[key] = value
        else
            copy[key] = deep_copy( value )
        end
    end
    return copy
end
   

This is a naïve implementation that does not copy metatables and keys that are tables (it's possible in Lua), and tables that include references to themselves, but it's likely to be enough for your purposes.

Further reading: https://www.lua.org/pil/2.5.html, starting from paragraph two.

P.S. A less naïve implementation, based on http://lua-users.org/wiki/CopyTable:

local function deep_copy( original, copies )
    if type( original ) ~= 'table' then return original end

    -- original is a table.
    copies = copies or {} -- this is a cache of already copied tables.

    -- This table has been copied previously.
    if copies[original] then return copies[original] end
    
    -- We need to deep copy the table not deep copied previously.
    local copy = {}
    copies[original] = copy -- store a reference to copied table in the cache.
    for key, value in pairs( original ) do
        local dc_key, dc_value = deep_copy( key, copies ), deep_copy( value, copies )
        copy[dc_key] = dc_value
    end
    setmetatable(copy, deep_copy( getmetatable( original ), copies) )
    return copy
end

Upvotes: 1

Related Questions