Search code examples
luametatable

table.insert doesn't trigger __index?


I made a custom table using metatables that automatically tracks sizing when elements are added. It works very well and removes the need for the # operator or the getn function.

However it has a problem. If you call table.insert, the function apparently never calls __index or __newindex. Thus, my table cannot know when elements are removed this way. I assume the problem is the same with table.remove as well.

How can I either:

  • Capture the event of insert and use my own function to do so
  • Throw an error if insert is called on my table.

Thanks

function Table_new()
    local public = { }
    local tbl = { }
    local size = 0

    function public.size()
        return size
    end

    return setmetatable(public, {
        __newindex = function(t, k, v)
            local previous_v = tbl[k]
            rawset(tbl, k, v)

            if previous_v ~= nil then
                if v == nil then
                    size = size - 1
                end
            elseif v ~= nil then
                size = size + 1
            end
        end,

        __index = tbl
    })
end

local t = Table_new()
t[5] = "hi"
t[17] = "hello"
t[2] = "yo"
t[17]  = nil
print(t.size()) -- prints 2

local z = Table_new()
table.insert(z, "hey")
table.insert(z, "hello")
table.insert(z, "yo")
print(z.size()) -- prints 1 -- why?

Solution

  • If you print k,v in __newindex, you'll see that k is always 1. This is because table.insert asks for the size of table to find where to insert the value. By default, it's at the end. You should add a __len metamethod. But perhaps this defeats your purposes (which are obscure to me).