Lua: Perfect Clone Function, Why not?

clone, lua, lua-table

Solution

To expand on @lhf's perfect note. I think this has been discussed on the Lua maillist on several occasions and I'd say there are two reasons for that: (1) what's perfect and reasonable for one case, is overkill for another one; (2) because of metamethods, upvalues, and circular references, it's difficult to cover various cases perfectly. For example, imagine you provide a proxy table using metamethods. Now, after cloning two of the tables share the same proxy table and whatever is stored by one is visible by another one. Is this a "perfect" clone or not?

On a more philosophical, but still relevant note. Perfection is difficult to achieve because of external links that objects have (and clones may need to preserve those; or not). You own a house. Does your perfect clone own the same house in the same way? Do you each now own 50% of the house? How about the third clone? Or you are happily married. How about your clone? Does the spouse need to be cloned as well? Where is the line between perfect and imperfect in this case?

By the time you care about the difference between deep and shallow copies, you can probably write your own function.

Problem

This is a question I have always wondered why it was not possible. Why can't a perfect clone function be made? Doesn't Lua 5.3 include a table.copy function...which I assume handles all problems/cases. By various clone functions I meant things like this (shallow, deep, recursive, etc)... ``` function deep (t) -- deep-copy a table if type(t) ~= "table" then return t end local meta = getmetatable(t) local target = {} for k, v in pairs(t) do if type(v) == "table" then target[k] = clone(v) else target[k] = v end end setmetatable(target, meta) return target end function shallow (t) -- shallow-copy a table if type(t) ~= "table" then return t end local meta = getmetatable(t) local target = {} for k, v in pairs(t) do target[k] = v end setmetatable(target, meta) return target end function copy1(obj) if type(obj) ~= 'table' then return obj end local res = {} for k, v in pairs(obj) do res[copy1(k)] = copy1(v) end return res end function copy2(obj) if type(obj) ~= 'table' then return obj end local res = setmetatable({}, getmetatable(obj)) for k, v in pairs(obj) do res[copy2(k)] = copy2(v) end return res end function copy3(obj, seen) if type(obj) ~= 'table' then return obj end if seen and seen[obj] then return seen[obj] end local s = seen or {} local res = setmetatable({}, getmetatable(obj)) s[obj] = res for k, v in pairs(obj) do res[copy3(k, s)] = copy3(v, s) end return res end ``` Sources: https://gist.github.com/MihailJP/3931841 and https://gist.github.com/tylerneylon/81333721109155b2d244 Can some explain why a perfect clone or copy function can't be made?

Original source