# Lua Metamethods #

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
--- This is a brief introduction to the concepts of Lua metamethods.
--- # Metamethods
--- Lua has a powerful extension mechanism which allows you to overload certain operations on Lua objets. Each overloaded
--- object has a metatable of function metamethods associated with it; these are called when appropriate, similar to
--- the concept of operator overloading from many other languages.
---
--- A metatable is a regular Lua table containing a set of metamethods, which are associated with events in Lua. Events
--- occur when Lua executes certain operations, like addition, string concatenation, comparisons etc. Metamethods are
--- regular Lua functions which are called when a specific event occurs. The events have names like "add" and "concat"
--- which correspond with string keys in the metatable like "__add" and "__concat". In this case to add(+) or concatenate
--- (..) two Lua Objects.
---
--- # Metatables
--- We use the function setmetatable() to make a table act as a metatable for a certain object.
---

local x = { value = 5 } -- creating local table x containing one key, value of value 5

local mt = {
__add = function(lhs, rhs)
-- "add" event handler
return { value = lhs.value + rhs.value }
end
}

setmetatable(x, mt) -- use "mt" as the metatable for "x"

local y = x + x
print(y.value) --> 10 print(y) will just give us the table code i.e table:<some tablecode>
local z = y + y --> error, y doesn't have our metatable. this can be fixed by setting the metatable of the new object inside the metamethod

--- When the addition operator finds that its operands aren't numbers, it tries checking if one of them has a metatable
--- with an _add key. In this case it does, so it runs the function stored under that key in the metatable, equivalent
--- to this: " local y = (getmetatable(x).__add(x,x)) -- x+x "
---
--- Metatables are still triggered with math operators if one of the operands is a number. And the left operand is
--- always the first parameter to the function, and the right operand is always the second. This means that the table
--- that has the metamethod might not necessarily be the first parameter to the metamethod.
---
--- # More events
--- The following are notes on other of the metamethod events that Lua handles.
---
--- ## __index
--- This is a very commonly used and versatile metamethod, it lets you run a custom function or use a "fallback" table
--- if a key in a table doesn't exist. If a function is used, its first parameter will be the table that the lookup
--- failed on, and the second parameter will be the key. If a fallback table is used, rememeber that it can trigger an
--- __index metamethod on it if it has one, so you can create long chains of fallback tables.
---

local func_example = setmetatable({}, { __index = function(t, k)
-- {} an empty table, and after the comma, a custom function failsafe
return "key does not exist."
end })

local fallback_tbl = setmetatable({
foo = "bar",
[123] = 446,
}, { __index = func_example })

local fallback_example = setmetatable({}, { __index = fallback_tbl }) -- {} again an empty table, but this time with a fallback failsafe

print(func_example[1]) --> key doesn't exist
print(fallback_example.foo) --> bar
print(fallback_example[123]) --> 456
print(fallback_example[456]) --> key doesn't exist

--- # __newindex
--- This metamethod is called when you try to assign to a key in a table, and that key doesn't exist(contains nil).
--- If the key exists, the metamethod is not triggered.
---

local t = {}
local m = setmetatable({}, { __newindex = function(table, key, value)
t[key] = value
end })

m[123] = 456
print(m[123]) --> nil
print(t[123]) --> 456

--- # Comparsion operators
--- __eq is called when the == operator is used on two tables, the reference equality check failed, and both tables
--- have the same __eq metamethod(!).
--- __lt is called to check if one object is "less than" another. Unlike __eq, it's not an error if the two objects have
--- differnent __lt metamethods, the one on the left will be used.
---
--- That's all you need for all of the comparison operators to work with your object. But there will be some cases where
--- both __lt and __eq will need to be called by the same operator. To avoid this, you can optionally add the __le
--- (less than or equal to) metamethod. Now only one of the metamethods will be called with any of the comparison operators.
---
--- For example, we can improve the example at the top of the page like this:
---

local mt
mt = {
__add = function(lhs, rhs)
return setmetatable({ value = lhs.value + rhs.value }, mt)
end,
__eq = function(lhs, rhs)
return lhs.value == rhs.value
end,
__lt = function()
return lhs.value < rhs.value
end,
__le = function(lhs, rhs)
return lhs.value <= rhs.value
end,
}

--- # __metatable
--- __metatable is for protecting metatables. If you do not want a program to change the contents of a metatable, you
--- set its __metatable field. With that, the program cannot access the metatable(and therefore cannot change it).
---
--- end.