In Lua, certain types (like tables) are always passed by reference, while other types (like numbers) are always passed by value.
Moreover, Lua is a language where memory is managed by garbage collector. Garbage collector deletes an object (a table, for instance), when there are no more references (let's call them anchors) to it.
Now this code:
local t = {}
local t1 = {t}
someFunc(t)
creates three anchors to that table. When someFunc passes another that table as an argument to another function, a fourth anchor will be created (in form of that function's local variable/argument).
In order for a garbage collector to sweep the first table, all those references must be gone (either by assigning nil or by going out of scope).
It's important to understand, that when you assign nil to the local t, it does not mean that the table will be deleted. Even less so that all references to that table will be invalidated. It means that you're just freeing this one anchor, which is just one of four at that point.
Possible solution
One possible solution would be to pass around the table holding your object along with the index/key, at which the object is stored:
function func(myTable, myKey)
...
end
Now if in this function you do this:
myTable[myKey] = nil
(and no other anchors get created), the object under the key will have no more references pointing to it and will be marked for sweeping by the garbage collector the next time round. Of course, callAnotherFunction would have to be modified in the same way as well:
callAnotherFunction(myTable, myKey)
...
end
If you perform many operations on that objects within those functions, you may cache it into a local variable to avoid several table lookups. This is ok, as when the function finishes, the anchor will be cleared along with the local variable:
callAnotherFunction(myTable, myKey)
    local myObj = myTable[myKey]
    ...
    if myCondition then myTable[myKey] = nil end
end  --here myObj is no longer valid, so the anchor is gone.
Another solution
Since you can't afford to change your code as much as suggested above, you could implement the following logic:
Create a metatable for tables that hold your objects:
local mt = {
    __newindex = function(tab, key, val)
        --if necessary and possible, perform a check, if the value is in fact object of your type
        val.storeTableReference(tab, key) --you'll have to implement this in your objects
        rawset(tab, key, val);
    end
}
local container1 = setmetatable({}, mt)
local container2 = setmetatable({}, mt)
Now when you insert an object into that table:
container1.obj1 = obj1
container2.obj1 = obj1
each time the __newindex metamethod will invoke obj1.storeTableReference with appropriate references. This function will store those references in (for instance) an internal table.
The only thing that's left to implement is a method for your object that frees those references:
myObj:freeReferences = function()
    for k, v in ipairs(self:tableReferences) do --assuming that's where you store the references
        k[v] = nil
    end
    tableReferences = {} --optional, replaces your reference table with an empty one
end
Now this solution is a bit clumsy, as there are a few things you need to be cautious about:
- __newindexonly get's fired when the key is first created. So- container1.obj = obj1and- container1.obj = obj2would only
trigger- __newindexon the first assignment. The solution would be
to first set the- objkey to nil and then to- obj2.
- when you set objto nil in that table manually (or to another
object), you need to make sure that the reference the object stores
gets cleared as well.