I have a code that displays the number of blocks that are in a field (field is a table), and how many blocks left until the field is empty. I am currently stuck with how to check when the table updates. I could use while do loops, but I want to avoid those
Metatables! (and metamethods :D)
What you're looking for is the __newindex
metamethod. Metamethods are like events, but for specific tables, called metatables
(see metatables: http://wiki.roblox.com/index.php?title=Metatable).
What are metatables?
So what are metatables? There are many analogies of a metatable being "a table inside a table" - though I strongly advise to neglect this description, for I don't find it relevant to what a metatable is at all.
A metatable is more of a secondary
table you can attach
to a "regular table". The metatable you attach to that regular table, can contain a dictionary
of functions that act as events on the table when certain procedures occur. These "events", are obviously referred to as metamethods as explained above (see metamethods: http://wiki.roblox.com/index.php?title=Metamethods)
Check when a table is changed?
Like I initially said, the metamethod you'd use to accomplish this task, would be __newindex
. The function you associate with this metamethod will execute whenever a new index is added to the table that the metatable belongs to. But first, let's create the metatable.
Creating a metatable
To create a metatable, we simply use the built-in setmetatable
function. This function takes two arguments:
1: The normal table
2: The metatable, with all it's metamethods.
The setmetatable
function also returns the normal table, so we can create it in one nice compact variable declaration, like this:
local t = setmetatable({} , {}) -- A blank normal table created, with a blank metatable attached.
How does __newindex work?
Now despite the name, it's important to know that __newindex will only execute if whatever "new index" you're trying to set, **doesn't exist**. This is why it's probably best to ensure you're starting with a blank table, so you can catch all the new keys that are added - if that is your intention.
Now I'm not going to cover all the metamethods - as there are quite a few - so I'll just be going over __newindex. To make this demonstration a bit clearer, I'll separate both the regular table, and the metatable with two different variables:
local normal = {} -- this will be our regular table local meta = {} -- this will be our metatable setmetatable(normal,meta) -- boom, now they're attached.
So now let's apply the __newindex metamethod to our "meta" table:
local normal = {} -- In dictionary format (i.e, having __newindex as the key, and it's function as the value). local meta = { __newindex = function() end } setmetatable(normal,meta)
Now the __newindex metamethod takes in 3 parameters:
1) The normal table
2) The key that's trying to be set
3) The value associated with that key
These parameters are often represented using a single letter, just to keep things simple. For example, the first parameter could be t
for table, the second could be k
for key, and the last could be v
for value - however the name of these parameters is completely up to you.
Full example
So now, let's cover a full example of how this would look adding a new index to a table, and watching the __newindex metamethod execute upon doing so:
local normal = {} local meta = { __newindex = function(t,k,v) -- This will print when a new key is added to the table print("The key: "..tostring(k).." has been added to the table.") end } setmetatable(normal,meta) normal.Hello = "Hello world" -- Invokes the __newindex metamethod.
IMPORTANT
Something very important to note here, is that table.insert
and table.remove
will NOT invoke these metamethods. So having the __newindex metamethod example I created above, will not execute if you inserted a value in the table via table.insert
- please remember that.
Questions
Hope that helped, let me know if you have any questions!
You have to use metatables. You can think of metatables as events for tables. They look different and work different, but achieve a similar purpose.
This blog post basically gives a complete tutorial, so there's no need for me to repost one. If you're interested, here's the wiki article, although I think the blog post is easier to understand.
One thing to note is that the __
(used before all metamethods) is two underscores. This can be confusing and hard to solve if you don't know about it. You need __
, not _