Skip to content

Instantly share code, notes, and snippets.

@RyanSquared
Last active October 24, 2023 09:23
Show Gist options
  • Save RyanSquared/b97be84fdee00c671f7ae26827cec1f3 to your computer and use it in GitHub Desktop.
Save RyanSquared/b97be84fdee00c671f7ae26827cec1f3 to your computer and use it in GitHub Desktop.

Lua OOP Tutorial

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.

Method 1

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.

Problems

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).

Method 2

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.

Notes

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).

Problems

Using this method doesn't have an easy way to create an inheritance format like extends or implements such as in other languages.

Method 3

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()

Closing Notes

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.

@PapaYofen
Copy link

what is self meaning in Method 3, it appear suddenly without context

@RyanSquared
Copy link
Author

I have resolved some issues and added some code comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment