Just to clarify, __newindex is only triggered when the previous value is nil. So the following code will trigger __newindex twice:
foo = {}
foo_mt = {
__newindex = function (t, k, v)
print (k, v)
rawset (t, k, v)
end
}
setmetatable (foo, foo_mt)
foo['oof'] = nil
foo['oof'] = nil
If foo['oof'] already has a non-nil value then __newindex will not be called (because the index already exists).
But yea, you need something like an empty proxy table if you want to catch all modifications to your table like Egor pointed out.
proxy = {}
foo = {}
foo_mt = {
__newindex = function (t, k, v)
print (k, v)
rawset (proxy, k, v)
end,
__index = function(t, k)
return rawget(proxy, k)
end
}
setmetatable (foo, foo_mt)
foo['ok'] = true
foo['ok'] = nil