Object-oriented programming in Lua is an often-debated topic and people normally assume that Lua, by default, has no way to implement object-oriented programming. However, obviously, there are multiple ways to implement object-oriented programming, which I will demonstrate in this article.
Object-oriented programming with objects can be easily done by passing an object (table) to a function and then have that function modify the table. Below will demonstrate an example of how this can be done with a "Hello World" constructor.
local function new_hello_world()
return {
format = "Hello %s.";
hello = "world";
}
end
local function set_hello(self)
self.hello = "world two"
end
local function print_hello(self)
print(self.format:format(self.hello))
end
local object = new_hello_world()
print_hello(object) --> Hello world.
set_hello(object)
print_hello(object) --> Hello world two.
This method is often times called "not object oriented" due to the methods not being accessible inside of the object. It's sometimes labelled as non-functional, despite being a form of programming that takes an object as input, uses the object, and produces information based on that object (the fact that you call print() doesn't count).
The first method didn't include the methods inside of the object so this next method will include the methods when returning the original object.
local function set_hello(self)
self.hello = "world two"
end
local function print_hello(self)
print(self.format:format(self.hello))
end
local function new_hello_world()
return {
format = "Hello %s.";
hello = "world";
set_hello = set_hello;
print_hello = print_hello;
}
end
local object = new_hello_world()
object:print_hello() --> Hello world.
object:set_hello()
object:print_hello() --> Hello world two.
Using the :
operator is the equivalent of using the .
operator
where the first argument is set to the left-hand side of the :
.
This makes hello:print()
equivalent to hello.print(hello)
.
Using this method doesn't have an easy way to create an inheritance
format like extends
or implements
such as in other languages.
Using an index
metavalue via setmetatable
lets tables use other
tables as a base to work off of without copying any values. With this
method, we'll take advantage of this to avoid duplicating entries.
local base_class = {
metatable = {
__index = base_class;
}
}
-- By defining the method with the `:` token instead of the `.` token,
-- it provides a `self` value which is passed through similar to
-- the previous functions.
function base_class:set_hello()
self.hello = "world two"
end
function base_class:print_hello()
print(self.format:format(self.hello))
end
function base_class.new()
return setmetatable({hello = "world"}, base_class.metatable)
end
local extended_class = {}
setmetatable(extended_class, {
__index = base_class;
}
local object = extended_class:new()
object:print_hello()
object:set_hello()
object:print_hello()
This is not the only way to implement OOP in Lua; there are other ways that work just as fine. This was a tutorial meant to teach how I personally implemented the format in Lua. I find no issues with this format so this is (a variation) of what I have implemented in my short library that implements a 'class' function in Lua.
what is self meaning in Method 3, it appear suddenly without context