Lua - Customizing Behavior with Metatables



Core power and purpose of metatable in Lua is in customizing the behavior of the Lua table. A metatable allows to change the default operation and we can define our own custom behavior as how to interact with a table. Using metatable and metamethods, we can handle almost all the events by which a table interaction happens.

How Customizing Works?

It is a three step process.

  • As first step, create a metatable. A metatable is a regular table with specialized fields. These fields can be assigned metamethods or table to hold custom behavior we want our table to exhibit.

  • In metatable, define the metamethods. We can assign metamethods to the predefined fields of metamethods. These fields always starts with __ like __index and so. The function assigned to such a field contains the custom logic for related event.

  • As last step, link the metatable. A metatable can be associated with the given table using setmetatable method. This effectively changes the behavior of the target table as per our custom metamethods.

When a certain behavior or event occurs on the table, Lua searches the relevant metamethod in the associated metatable and executes the same. Following is an example of setting default values for values of a table.

Example - Setting default values using Metatable

main.lua

-- Default values
local defaults = { width = 100, height = 50 }

-- main table
local shape = {}

-- metatable
local meta = { __index = defaults }

-- set metatable
setmetatable(shape, meta)

-- get default values of keys
-- prints 100
print(shape.width) 
-- prints 50
print(shape.height)
-- prints nil, as not present in defaults
print(shape.color)

Output

When we run the above program, we will get the following output−

100
50
nil

Applications of Metatables in Customization

Lua metatable is a powerful concept to do customization to the behavior of a table for a wide range of operations. Following is the list of some of areas where we can use metatables to do customization −

  • OOPS implementation − We can implement Object Oriented Concepts like inheritance, encapsulation using private methods, controlled access to some operations and so on.

  • Custom Datastructure − We can create specialized data structures like stack, queue using metatables to exhibit specific behaviors.

  • Controlled Access − We can decide to make a table as readonly, perform validation on data before assigning to the table.

  • Operator Overloading − We can overload operators like +, == and so to make code more natural with tables.

  • String Representation − We can decide a string representation of a table or object.

  • Protect Underlying Implementation − We can protect internal functioning of certain operation by limiting access to them.

Advertisements