I’m not new to using Metatables, however I haven’t used Metamethods like this before, thus I require assistance with getting this code to work as expected and to understand index & newindex
local Table = setmetatable({},{
__index = function(self,index)
print("__index",self,index)
return rawget(self,index)
end,
__newindex = function(self,index,value)
print("__newindex",self,index,value)
rawset(self,index,value)
end,
})
Table.A = 1
Table.A = 2
if Table.A then
print(Table.A)
end
--[[ Output
__newindex table: 0xfde0cf082ad17e64 A 1
2
--]]
--[[ Expected Output
__newindex table: 0xfde0cf082ad17e64 A 1
__newindex table: 0xfde0cf082ad17e64 A 2
__index table: 0xfde0cf082ad17e64 A
__index table: 0xfde0cf082ad17e64 A
2
--]]
There wasn’t a lot of materials on index & newindex to begin with and I didn’t find a similar Thread, so if you do please let me know.
First of all thank you for reading my article hehe!
Remember that after this line
Table.A = 1
You’re setting the key A inside of Table (with rawset inside of __newindex), meaning the next time you do Table.A = 2 you’re not gonna fire __newindex because now A exists. Also __index won’t fire because A exists as well so you’re not indexing something that is nil.
Ah I see what you’re doing! Well this concept is actually a thing used very often in lua, it’s called a proxy table, the PIL does a great job explaining it. Here is a link. If you find yourself not understanding something about it I’m happy to answer
Although it’s already answered, I’ll share an implementation using Bindables (yeah networking and such) for a table.changed.
To get __newindex to trigger for existing values you’ll need a proxy table as starmaq already said.
Alternatively you could create an identical table and set __newindex to check whether a certain index has the same value as the one being set to the index and then fire the bindable passing the index and value (if what you want is the __newindex firing for existing values apparently).
local data = {}
function data:__call(t)
assert(type(t) == "table", ("bad arg #1 table expected, got %s"):format(type(t)))
local t2 = t
local bindable = Instance.new("BindableEvent")
t = setmetatable({}, {
__index = t,
__newindex = function(self, index, value)
if t2[index] ~= value then
bindable:Fire(index, value)
rawset(t2, index, value) -- C stack overflow no more
end
end
})
t.Changed = bindable.Event
return t
end
return setmetatable(data, data)
-------
local data = require(module)({coins = 1, cash = 5})
data.Changed:Connect(print)
data.coins = 1 -- nothing
data.coins = 10 -- prints 'coins 10'