In this article, we’ll explore the concept of Lua metatables, how to use them, and some practical examples.
Tables that define the behavior of other tables are known as metatables.
Lua metatable is a table that is associated with another table, and which provides additional functionality to that table.
A metatable can be used to customize the behavior of tables in various ways, such as changing how Lua performs arithmetic operations on them, or adding new methods and properties to tables.
Metatables can also be used to create custom data-types in Lua, and to implement object-oriented programming techniques.
In Lua, every table can have a metatable associated with it, and this metatable can be accessed and modified using the setmetatable and getmetatable functions.
The setmetatable function sets the metatable of a table, while the getmetatable function retrieves the metatable of a table.
This method sets the metatable of a table. Here ‘table’ is the table whose metatable is to be set, and ‘metatable’ is the new metatable to be assigned to the table.
The following example illustrates the setmetatable() function in Lua:
-- Define a table
local myTable = { 2, 4, 6, 8, 10 }-- Define a metatable with custom behavior
local myMetatable = {
__tostring = function(t)
return "This is myTable with values: " .. table.concat(t, ", ")
end,
__add = function(t1, t2)
local result = {}
for i = 1, #t1 do
result[i] = t1[i] + t2[i]
end
return result
end
}
-- Set the metatable for myTable
setmetatable(myTable, myMetatable)
-- Use the __toString metamethod
print(myTable)
local myOtherTable = { 1, 2, 3, 4, 5 }
-- Use the __add metamethod to add two tables
local sum = myTable + myOtherTable
print('Values after using __add metamethod:',table.concat(sum, ", "))
This method gets the metatable of a table. The getmetatable() function takes a single argument, which is the table whose metatable we want to retrieve.
If the table has a metatable, getmetatable() returns it.
If the table does not have a metatable, getmetatable() returns nil.
Below example explains the usage of getmetatable() method:
-- Define a table and a metatable
local mytable = {a = 1, b = 2}
local mymetatable = {c = 3, d = 4}-- Set the metatable for the table
setmetatable(mytable, mymetatable)-- Get the metatable for the table
local retrievedMetatable = getmetatable(mytable)if retrievedMetatable == mymetatable then
print("Retrieved metatable is the same as the original metatable")
else
print("Retrieved metatable is NOT the same as the original metatable")
end
Metamethods are special methods in Lua that are associated with metatables and define the behavior of operators and built-in functions when applied to tables.
In other words, metamethods provide a way to extend or modify the behavior of Lua’s built-in operators and functions when applied to tables.
Lua Metatables must first be created as regular tables before they can be used.
There are several metamethods in Lua, each corresponding to a specific built-in operator or function.
One or more of the following metamethods should be included in this table:
__index
Used when a non-existent key is used to index the table.
Here is an example that uses the __index metamethod:
-- Define a table with some default values
local myTable = {
name = "John",
age = 35,
occupation = "Programmer"
}-- Define a new table with a metatable that has an __index metamethod
local myMetatable = {
__index = function(table, key)
if key == "gender" then
return "Male"
else
return "Unknown"
end
end
}-- Set the metatable for myTable to myMetatable
setmetatable(myTable, myMetatable)-- Try to access a key that doesn't exist in myTable
print(myTable.address) -- Output: Unknown-- Try to access the "gender" key that doesn't exist in myTable but specified using __index
print(myTable.gender) -- Output: Male
__newindex
When a new index is set on a table, this function is called.
Below example examines the __newindex method in Lua:
local mytable = {}local mymetatable = {
__newindex = function (table, key, value)
print("Assigning value " .. value .. " to key " .. key)
end
}setmetatable(mytable, mymetatable)mytable.name = "Harry"
__toString
This method allows us to define how an object should be converted to a string when it is printed.
This method is called by the tostring() function when it is called on an object.
Following example simplifies the understanding of the __toString method:
local mytable = {name = "Harry", age = 35}local table_metatable = {
__tostring = function(table)
return "Name: " .. table.name .. ", Age: " .. table.age
end
}setmetatable(mytable, table_metatable)print(mytable)
__add
This function is called when two values are added.
Let’s explore an example where _add is implemented:
local myTable = {value = 20}-- define a metatable with an __add metamethod
local myMetatable = {
__add = function(table1, table2)
return {value = table1.value + table2.value}
end
}-- set the metatable of myTable to myMetatable
setmetatable(myTable, myMetatable)-- define another table with a value of 5
local anotherTable = {value = 5}-- add the two tables together
local result = myTable + anotherTable-- print the result
print(result.value)
__sub
This method triggers when two values are subtracted with the – operator.
Below example showcases the implementation of __sub metamethod in Lua:
local myTable = {value = 20}-- define a metatable with a __sub metamethod
local myMetatable = {
__sub = function(table1, table2)
return {value = table1.value – table2.value}
end
}-- set the metatable of myTable to myMetatable
setmetatable(myTable, myMetatable)-- define another table with a value of 5
local anotherTable = {value = 5}-- subtract the two tables
local result = myTable – anotherTable-- print the result
print(result.value)
__mul
This method is invoked when two values are multiplied using the * operator.
The following example provides an overview of the __mul metamethod in Lua:
local myTable = {value = 20}-- define a metatable with a __mul metamethod
local myMetatable = {
__mul = function(table1, table2)
return {value = table1.value * table2.value}
end
}-- set the metatable of myTable to myMetatable
setmetatable(myTable, myMetatable)-- define another table with a value of 5
local anotherTable = {value = 5}-- multiply the two tables together
local result = myTable * anotherTable-- print the result
print(result.value)
__div
This method is called if two values are divided using a / operator.
The __div method is demonstrated in the example below:
local myTable = {value = 20}-- define a metatable with a __div metamethod
local myMetatable = {
__div = function(table1, table2)
return {value = table1.value / table2.value}
end
}-- set the metatable of myTable to myMetatable
setmetatable(myTable, myMetatable)-- define another table with a value of 5
local anotherTable = {value = 5}-- divide the two tables
local result = myTable / anotherTable-- print the result
print(result.value)
__mod
Used when two values are divided using the % operator.
The following example implements the __mod metamethod in Lua:
local myTable = {value = 20}-- define a metatable with a __mod metamethod
local myMetatable = {
__mod = function(table1, table2)
return {value = table1.value % table2.value}
end
}-- set the metatable of myTable to myMetatable
setmetatable(myTable, myMetatable)-- define another table with a value of 5
local anotherTable = {value = 5}-- perform mod operation between the two tables
local result = myTable % anotherTable-- print the result
print(result.value)
__pow
This function is called when one value is raised to the power of another using the ^ operator.
Let’s understand the __pow metamethod using an example:
local myTable = {value = 20}-- define a metatable with a __pow metamethod
local myMetatable = {
__pow = function(table1, table2)
return {value = table1.value ^ table2.value}
end
}-- set the metatable of myTable to myMetatable
setmetatable(myTable, myMetatable)-- define another table with a value of 5
local anotherTable = {value = 5}-- perform exponentiation operation between the two tables
local result = myTable ^ anotherTable-- print the result
print(result.value)
__unm
This function is invoked when a value is negated using the – operator.
Now let’s explore the __unm metamethod using an example:
local myTable = {value = 20}-- define a metatable with a __unm metamethod
local myMetatable = {
__unm = function(table1, table2)
return {value = -table1.value}
end
}-- set the metatable of myTable to myMetatable
setmetatable(myTable, myMetatable)-- perform unary minus operation on table1
local result = -myTable-- print the result
print(result.value)
__eq
Triggered when two values are compared using the == operator.
Below example explains further the __eq metamethod in Lua:
local myTable = {value = 20}-- define a metatable with an __eq metamethod
local myMetatable = {
__eq = function(table1, table2)
return table1.value == table2.value
end
}-- set the metatable of myTable to myMetatable
setmetatable(myTable, myMetatable)-- define another table with a value of 20
local anotherTable = {value = 20}-- Equality comparison between the two tables
local result = myTable == anotherTable-- print the result
print(result)
__lt
Executed when two values are compared using the < operator.
Using this example, the __lt metamethod in Lua is implemented:
local myTable = {value = 20}-- define a metatable with a __lt metamethod
local myMetatable = {
__lt = function(table1, table2)
return table1.value < table2.value
end
}-- set the metatable of myTable to myMetatable
setmetatable(myTable, myMetatable)-- define another table with a value of 30
local anotherTable = {value = 30}-- Less than comparison between tables
local result = myTable < anotherTable-- print the result
print(result)
__le
When two values are compared using the <= operator, this function is called.
This example is used to examine the __le metamethod in Lua:
local myTable = {value = 20}-- define a metatable with an __le metamethod
local myMetatable = {
__le = function(table1, table2)
return table1.value <= table2.value
end
}-- set the metatable of myTable to myMetatable
setmetatable(myTable, myMetatable)-- define another table with a value of 25
local anotherTable = {value = 25}-- Less than or equal to comparison between tables
local result = myTable <= anotherTable-- print the result
print(result)
__call
This method gets
invoked when a table is called like a function.
Below example utilizes the __call metamethod in Lua:
-- create a table
local myTable = {}-- define a metatable for myTable with an __call metamethod
local myMetatable = {
__call = function(name)
local str = "Hello John"
return str
end
}-- set the metatable of myTable to myMetatable
setmetatable(myTable, myMetatable)-- call myTable as a function
local result = myTable()-- print the result
print(result) -- should print "Hello John" to the console
Lua Metatables provide several benefits, including:
- Metatables allow you to customize the behavior of tables in Lua. This can be used to implement various programming paradigms, such as object-oriented programming, or to add custom functionality to tables.
- By defining metatables, you can reuse the same code across multiple tables, rather than writing the same code repeatedly.
- Lua metatables allows you to extend the functionality of Lua’s built-in types, such as tables and numbers. This can be useful when working with complex data structures or when implementing domain-specific functionality.
- Lua metatables can be used to provide a layer of security to Lua programs, by preventing access to certain methods or properties of tables.
- Lua metatables can be used to optimize the performance of Lua programs, by providing custom implementations of common operations, such as indexing and arithmetic operations.