Greetings! This is my first-ever community tutorial, so please do not hesitate to send feedback.
What you need to know before reading this:
- Complex numbers (optional, it just makes this easier to understand)
- Metatables:
- OOP in general: All about Object Oriented Programming (also linked again later on)
If you’re familiar with Python magic methods, you can stop here; Lua metamethods are similar.
Here’s a list of existing metamethods to get you started: lua-users wiki: Metatable Events
Here’s the documentation for Python if you’re interested:
I haven’t seen any community tutorials on this, and I think it’s very useful in making your modules function in a more user-friendly way for other developers, and adds some useful behaviour too (e.g. printing out a message)!
As an example, let’s say you created a complex numbers module and it works like this:
local ComplexModule = require(ComplexModule)
local a = ComplexModule.New(0, 5) -- 0 is real, 5 is imaginary
local b = ComplexModule.New(2, 3)
-- addition
local result = a:Add(b)
result:PrintResult() -- You can't directly call print(), as it'll give you
-- an unreadable format, so you would probably
-- make a custom method.
Now, what if I told you that this is possible:
local ComplexModule = require(uhh)
local a = ComplexModule.New(0, 5) -- 0 is real, 5 is imaginary
local b = ComplexModule.New(2, 3)
-- look! You can add them together directly, how convenient!
-- and you can also directly use print()!
print(a + b)
This is the magic of lua magic methods.
Many of you should already be familiar with the .__index
added to the end of a metatable for
OOP. If you want to know what .__index
does, here’s a really good tutorial.
Here’s an example - inside the ComplexModule
local complex_object = {}
complex_object.__index = complex_object
-- constructor
-- If you're unsure what this does, please read up on OOP first!
function complex_object.New(real: number, imaginary: number)
local self = {}
-- setting properties
self.Real = real
self.Imaginary = imaginary
setmetatable(self, complex_object)
return self
end
-- maths operator: +
-- functionality for: complex_a + complex_b
function complex_object.__add(complex_a: complex_object, complex_b: complex_object)
complex_a.Real += complex_b.Real
complex_a.Imaginary += complex_b.Imaginary
return complex_a
end
Here we’re telling what the interpreter does when it tries to add two complex numbers together. I.e.:
complex_a + complex_b
.
The .__add()
magic method takes in two arguments, both should be of the same type (you can’t add numbers to strings!). The first argument will be the object to the left of the +
operator. The second argument will be the object to the right of the operator.
All magic methods can only return 1 result, with a few exceptions.
You can use this to create custom behaviours for addition, subtraction (.__sub
), multiplication (.__mul
) and more!
Another example:
-- comparison operator: ==
-- functionality for: complex_a == complex_b
function complex_object.__eq(complex_a: complex_object, complex_b: complex_object)
local real_equiv = complex_a.Real == complex_b.Real
local imaginary_equiv = complex_a.Imaginary == complex_b.Imaginary
return real_equiv and imaginary_equiv
end
This time we’re telling the interpreter what to do when ==
two objects. Naturally, this should return a boolean. The reason you might do this is the default ==
just wouldn’t work for you. As without our function here, it would compare the entire metastable.
Final example (which is how to get print() working)
function complex_object.__tostring(complex: complex_object)
return tostring(complex.Real) .. " + " .. tostring(complex.Imaginary) .. "j"
end
Some functions may use magic methods too. E.g. print()
. If it can find an existing .__tostring
then it will use that. Similarly, you can also use .__name
which may be used by tostring()
and error messages.
Now you can define behaviour for mathematical operations, comparisons and more!
As a freebie, here’s a module I made which I took all these examples from: https://create.roblox.com/marketplace/asset/15174197720
Happy coding