Welcome to the PtokaX Wiki!
This wiki is devoted to let users share information on the great hubsoft PtokaX. However, it is not limited to PtokaX, it is destined to share and discuss information on different parts of the LUA programming language, but the site is NOT intended to be a replacement for the primary LUA Board aka the PtokaX Portal, nor the secondary LUA Board or the PtokaX resources.
If you’re not familiar with wikis then in short: they are user-contributed sites: pages can be edited by (almost) anyone. As such, there is always kind of up-to-date and (hopefully) proper content. They are better than forums, since relevant pieces of information are on the same page. Do not hesitate to share your knowledge, and we all hope you can learn and teach a lot here! — bastya_elvtars
Trace: » The Operating System Library in Lua 5.1.x » Introduction » Using the string library in LUA » Tips on scripting in API v.2 » main » API 2 Script Examples » Setting up PtokaX » PtokaX Service Installation Guide » File manipulation » Metatables and metamethods
Metatables and metamethods
Meta means modifier in this context, and indeed: it does alter the behaviour of a table. Using metatables, you can change the default values of keys in a table, call merge tables or print them out with the print command directly, and much more.
General considerrations
Creating a metatable, general properties of metatables.
A metatable is an ordinary table, but it has special fields. Any table can be the metatable of any other table; a group of related tables may share a common metatable (which describes their common behavior); a table can be its own metatable (so that it describes its own individual behavior). Any configuration is valid.
Look at this piece of code:
t={} mt={} setmetatable(t,mt)
The C function setmetatable gets 2 arguments: the table and the metatable. If the metatable is nil, removes the metatable of the given table. If the original metatable has a __metatable field, raises an error.
Metamethods in general
Metamethods are functions inside a metatable that are fired on certain events happening to the original table. A complete list of metamethods can be found here. These will be dealt with below.
Declaring a methamethod is like any function declaration:
mt.__newindex=function(tbl,k,v) print("[\""..k.."\"]="..v.." added"); rawset (tbl,k,v) end
Ouch! This looks frightening, but you will understand this and see how you can unleash the real power of LUA.
Metamethods in detail
__index
This metamethod is fired, when a non-existant index is sought for in the table. It can (or should?) have a return value, and in this case, the lookup gets that as value.
The function gets 2 arguments: the table and the key accessed.
An example:
ASCII= { ["a"]=97, ["b"]=98, ["c"]=99 } MyMetaTbl= { __index=function(tbl,k) -- fired whenever a non-existant key is sought for if type(k)=="string" and string.len(k)==1 then -- we want 1-char strings only return string.byte(k) -- we do return the ascii value end end } function GetChar(char) -- we set the metatable here, since there is a variable -- living only inside the function's scope, -- referred to as v inside the metamethod setmetatable(ASCII,MyMetaTbl) -- here comes the definitive access print(ASCII[char]) end -------------------- -------------------- GetChar("U")
__newindex
It is fired when a new index (previously non-existant) is created in the table. The function gets 3 values: the table itself, the key, and the value that were newly created.
Example 1: Read-only tables
mt= { __newindex=function(tbl,key,val) print("Don't try to write into a read-only table you fool!") end } function Add(key,val) setmetatable(tab,mt) tab[key]=val end ------------------ ------------------ Add("hey","you")
rawset and rawget
These methods set/get values in tables using a raw way: metamethods are completely ignored thus they are mostly used inside methatmethods, since a table[key]=value call
inside the metamethod would fire up the metamethod again.
rawset gets 3 arguments: table, key, value. rawget gets 2 arguments: table and key, it returns the value belonging to a key if any.
For pure fun, let's see an example that uses metamethods and clones how tables work when there are no metamethods.
tab={} mt= { __newindex=function(tbl,key,val) rawset(tbl,key,val) end, __index=function(tbl,key) return nil end } function Add(key,val) setmetatable(tab,mt) tab[key]=val end ------------------ ------------------ Add("hey","you")
A complete example
We store data in a metafile in the format key|value. We need to lookup using keyas and values as well. Now when we load a table from a file, it automatically adds the correspondent entries to the 'reverse' table.
--[[ You need a file called test.txt in the same dir as this script. Looking like: a|1 b|2 c|3 d|4 ]] tab={} tab2={} mt={ __newindex=function(tbl,k,v) print("adding "..v.." as key, "..k.. " as val") tab2[v]=k; rawset(tab,k,v) end } function AddToTable(k,v) setmetatable(tab,mt) tab[k]=v end local f=io.open("test.txt") if f then for line in f:lines() do local _,_,k,v=string.find(line,"(.+)|(.+)") if k and v then AddToTable(k,v) end end f:close() end for a,b in pairs(tab) do print("tab",a,b) end for a,b in pairs(tab2) do print("tab2",a,b) end
You are here: About the Wiki » scriptinghelp » Metatables and metamethods