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



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. :-D

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

Personal Tools