but this will get confusing for sure.
I'm still very new to LUA and one thing i haven't worked much yet with is metatables.
I need to find a way to create a meta table which runs a function on editing values. This is not a problem if i stay on "one level", so the first index. Then i can simply use the __newindex to run it. But what i'm trying to do is to run the function whenever any value is changed.
This would require some way to set any table inside the metatable to be again a metatable running the same function as the "main" metatable
In my use case that would be a "save" function:
function MySaveFunction(tbl)
FileSave(my_settings_path, tbl)
end
MyTable = setmetatable()
MyTable.Value = value --> run MySaveFunction(MyTable.Value)
MyTable.SubTable = {} --> run setmetatable() on SubTable
MyTable.SubTable.Value = value --> run MySaveFunction(MyTable.SubTable.Value)
MyTable.SubTable.SubSubTable = {} --> run setmetatable() on SubSubTable
MyTable.SubTable.SubSubTable.Value = value --> run MySaveFunction(MyTable.SubTable.SubSubTable.Value)
MyTable.SubTable.SubSubSubTable = {} --> run setmetatable() on SubSubSubTable
MyTable.SubTable.SubSubSubTable.Value = value --> run MySaveFunction(MyTable.SubTable.SubSubSubTable.Value)
Hope someone can help me <.<
First thing to take a note of is that
__newindex
and__index
metamethods are only triggered when they handlenil
value in target table. If you want to track every single change, you can't just use__newindex
, because once you write a value, subsequent calls won't do anything. Instead, you need to use a proxy table.Another important thing to consider is tracking paths of accessed members.
Last, but not least, you need to remember to use raw access functions like e.g.
rawget
when implementing your handlers. Otherwise, you may encounter stack overflows or other weird behaviour.Let's have a trivial example to illustrate the problems:
Now, we need to deal with them. Let's start with a way to create a proxy table:
This way you have three tables: proxy, metatable and data. User accesses proxy, but because it's completely empty on each access either
__index
or__newindex
metamethods from metatable are called. Those handlers access data table to retrieve or set the actual values that user is interested in.Run this in the same way as previously and you will get an improvement:
This should give you an overview on why you should use a proxy table here and how to handle metamethods for it.
What's left is how to identify the path of the field that you are accessing. That part is covered in another answer to another question. I don't see a reason to duplicate it.