Metatables

This page describes advanced techniques using metatables.

Why Meta-?

Meta means here "something between something". Meta information are information on something to tell the machine how to treat it. In databases, meta information is a collection of access times, acces codes and so on which is used for optimizing the database.

In Lua, metatables have a alike function. Metatables are describing objects (tables) how a table is going to be treated when accessing.

What are metatables doing in Lua?

Generally, you can store information in metatables and you can overload operators for an object. Formerly, in Lua 5.0 only tables and userdatavalues had metatables. Since Lua 5.1, every type in lua has a metatable.

What operators can be overloaded?

Every operator in Lua can be overloaded. This means:
  • Arithmetic Operators
+ - * % / ^
  • Relational Operators
== ~= < > <= >=
  • Logical Operators
and or not
  • Concatenation, length, index and call operator
.. # [] . ()

An additional garbage collection call can also be overloaded which is called when the garbage collection is being done on that particular object. Another metamethod is __tostring, which is called whenever the function tostring is called with the object as argument.

What can operator overloading do?

Metatables can change the "behaviour" of an object. A very useful application is creating an object oriented system - although lua does not offer object orientation.

__index and __newindex

A common way in object oriented languages is to create a class that provides the functions while the object itself contains only the data values of the object that is instantiated from the class using a new operator, which is provided in many languages i.e. Java or C++. We can mimic this behavior in lua using metatables:

myclass = {}
mymetatable = {__index = myclass}
function myclass.new (objectvalues)
  local self = {value = objectvalue}
  setmetatable(self,mymetatable)
  return self
end

function myclass:print()
  print(self.value)
end

obj = myclass.new("hello world")
obj:print()
obj.anothervalue = 123
print(obj.print, obj.anothervalue)

Output:

 hello world
 function 003DC0F8   123

We call the function myclass.new which creates a table with an initial value named value. The myclass table has a registered function which is called foo. The : operator here is just a helper - it would be exactly the same if we wrote function myclass.print (self) - it only appends a variable named self as first argument. If we later call the function using the created object, the object variable is passed as first argument, so writing obj.print(obj) is equivalent to obj:print().

The metatable that we specified above is does this:

  • If the table has a value of the searched name, return the table's value
  • If it has not (nil), return the value of the same key in the table that __index points to. The result may be nil, but in the example above it returns myclass.print since obj.print does not exist. This is same as if we wrote myclass["print"].

The __index value is only looked up if we look up a value. If we create a new index value, it is not touched which results in this behaviour:
obj = myclass.new("hello world")
obj:print()
obj.print = function (self)
  print("my value is:",self.value)
end
obj:print()
myclass.print(obj)

Output:

 hello world
 my value is:   hello world
 hello world

What we did here is, that we created a new entry in the table object of the same name as in the table myclass. So any access on the obj table with the key print will return our newly created function - and not the myclass.print function. However, the original function in myclass is not touched. This is also the first example that shows how to overload functions in an object oriented way we can use lua.