|
| 1 | +# Lua Metatables |
| 2 | + |
| 3 | +Lua is a minimalistic but powerful scripting language, that only provides few smart mechanisms and doesn't anything, |
| 4 | +which gives us a lot of freedom. One of these mechanisms is the *metatable*. I don't even know if other languages have |
| 5 | +such thing. Some people think that *metatables* are the Lua *classes*, but that is not really true. Yes, you can mimic OOP |
| 6 | +using *metatables*, but as mentioned before Lua doesn't enforce anything and you can use them for whatever you can think of. |
| 7 | + |
| 8 | +It is very helpful if you, the reader, have already understood ... |
| 9 | + |
| 10 | +- tables |
| 11 | +- functions |
| 12 | +- nil |
| 13 | + |
| 14 | +... otherwise this *metatable* introduction won't make much sense. |
| 15 | + |
| 16 | +## The Basics |
| 17 | + |
| 18 | +A *metatable* (let's call it `M`), is also just a simple table, but with [specific indices](https://www.lua.org/manual/5.4/manual.html#2.4) |
| 19 | +and it has to be declared to be the *metatable* of "another" table (let's call that `T`) using the `setmetatable(T,M)` function. These specific |
| 20 | +indices or metatable elements act as events. And when one of these events is triggered then Lua can execute something. |
| 21 | +You can simply treat these indices as reserved for Lua metatables, and therefore not use them for anything else but |
| 22 | +metatables, otherwise you would confuse people reading your code, and probably yourself too. |
| 23 | + |
| 24 | +Let's see which events exist, and what would trigger these events. |
| 25 | + |
| 26 | +- `__index` ➞ when you are accessing a key/index that is not present in the table T. |
| 27 | +- `__newindex` ➞ when you are trying to create a new key/index inside the table T |
| 28 | +- `__call` ➞ when you are calling a table like a function `T()`. |
| 29 | +- Operators ➞ When you use an operator on 1 or 2 tables ... |
| 30 | + - `__add` ➞ `t1 + t2` |
| 31 | + - `__sub` ➞ `t1 - t2` |
| 32 | + - `__mul` ➞ `t1 * t2` |
| 33 | + - `__div` ➞ `t1 / t2` |
| 34 | + - `__mod` ➞ `t1 % t2` |
| 35 | + - `__pow` ➞ `t1 ^ t2` |
| 36 | + - `__unm` ➞ `-t1` |
| 37 | + - `__idiv` ➞ `t1 // t2` |
| 38 | + - `__band` ➞ `t1 & t2` |
| 39 | + - `__bor` ➞ `t1 | t2` |
| 40 | + - `__bxor` ➞ `t1 ~ t2` |
| 41 | + - `__bnot` ➞ `~t1` |
| 42 | + - `__shl` ➞ `t1 << n` |
| 43 | + - `__shr` ➞ `t1 >> n` |
| 44 | + - `__concat`➞ `t1 .. t2` |
| 45 | + - `__len` ➞ `#t1` |
| 46 | + - `__eq` ➞ `t1 == t2` |
| 47 | + - `__lt` ➞ `t1 < t2` |
| 48 | + - `__le` ➞ `t1 <= t2` |
| 49 | + |
| 50 | +Okay, now let's write a small and almost finished code example that shows how to create a *metatable* and how to use `setmetatable()`. |
| 51 | + |
| 52 | + T = { } |
| 53 | + |
| 54 | + M = |
| 55 | + { |
| 56 | + __index = <placeholder>, |
| 57 | + __newindex = <placeholder>, |
| 58 | + __call = <placeholder>, |
| 59 | + __add = <placeholder>, |
| 60 | + } |
| 61 | + |
| 62 | + setmetatable(T, M) |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | + |
| 67 | +Now we have a metatable `M` that **is connected** to the table `T`. We defined some events in our *metatable*, so that it's clear |
| 68 | +**when** to do something. And now only the actions are missing. The `<placeholder>`s are the actions - the "**what** to do"s. |
| 69 | +And what do we usually associate with actions? - functions. All of them can be functions, but `__index` and `__newindex` |
| 70 | +can also be tables instead of functions, which is actually pretty common. |
| 71 | +But for now let's focus on the functions, that only print some text, and let's try to trigger these events. |
| 72 | + |
| 73 | + T = { } |
| 74 | + |
| 75 | + M = |
| 76 | + { |
| 77 | + __index = function() print("this key does not exist in table T") end, |
| 78 | + __newindex = function() print("you want to create a new key in table T") end, |
| 79 | + __call = function() print("you are calling T like a function") end, |
| 80 | + __add = function() print("you are using the + operator") end, |
| 81 | + } |
| 82 | + |
| 83 | + setmetatable(T, M) |
| 84 | + |
| 85 | + -- trigger the __index event by accessing a non-existing index |
| 86 | + local Foo = T.foo |
| 87 | + |
| 88 | + -- trigger the __newindex event by creating a new index |
| 89 | + T.foo = 123 |
| 90 | + |
| 91 | + -- trigger the __call event by calling the table like a function |
| 92 | + T() |
| 93 | + |
| 94 | + -- trigger the __add event by providing tables as operands to the plus operator |
| 95 | + local Sum = T + T |
| 96 | + |
| 97 | + |
| 98 | +If you execute this it prints ... |
| 99 | + |
| 100 | + this key does not exist in table T |
| 101 | + you want to create a new key in table T |
| 102 | + you are calling T like a function |
| 103 | + you are using the + operator |
| 104 | + |
| 105 | + |
| 106 | +Now we have learned the very basics of *metatables*, but this is the most important part, because it explains the event |
| 107 | +concept. At the moment the functions don't do much except for the printing, and therefore we will learn in the next chapter |
| 108 | +about the parameters of the *"event-action"* functions we just created. |
| 109 | + |
0 commit comments