OOP... _index ... self ... what?!

Hi there! I’m moose, and I’ve been recently trying to make some weapons systems, as I found them to be interesting! And now I’ve been looking into some code done by a programmer, and I almost fainted. There were so many “self” and “_index” and so much stuff which was completely incomprehensible for me! I tried looking into metatables, and OOP, and I understand less and less by the minute. I have looked into every forum page, and I have always been of the idea that tables can have a bunch of variables, not that they can be “objects” or have metatables! That’s all. I would love an answer to how OOP works to someone who learning lua learnt about “death blocks” that would set your health to 0 or neon chaning blocks. I have not the slightest clue what methods or objects are… :slight_smile: Anyway, if any people have an answer, I’d be happy to read.

I’d recommend starting off by learning without an object-oriented approach to understand the fundamentals of Luau. But to break it down for you…

OOP is a programming paradigm that uses “objects” to model real-world entities:
Using OOP in Lua with metatables allows you to create more organized and modular code by encapsulating related data and functions within the object itself.

  • Table as an Object: In Lua, tables can be used to represent objects. Each object can have its own properties (variables) and methods (functions).
  • Metatable: A table that defines behaviour for another table. It’s like a “meta” level that allows you to define custom behavior.
  • __index: A key in a metatable that is used to look up values. When you try to access a key that doesn’t exist in a table, Lua checks the __index field of the metatable.
  • self: Refers to the instance of the object itself. When you call a method on an object, self is used to access its properties and other methods.

Here’s an easy example:
Step 1: Define your class

-- Create a table to represent the class
local Weapon = {}
Weapon.__index = Weapon

-- Constructor function
function Weapon:new(name, damage)
    local instance = setmetatable({}, Weapon)
    instance.name = name
    instance.damage = damage
    return instance
end

-- Method to display weapon details
function Weapon:display()
    print("Weapon: " .. self.name .. ", Damage: " .. self.damage)
end

Step 2: Create instances of your class:

-- Create instances of the Weapon class
local sword = Weapon:new("Sword", 50)
local bow = Weapon:new("Bow", 30)

-- Call methods on the instances
sword:display()  -- Output: Weapon: Sword, Damage: 50
bow:display()    -- Output: Weapon: Bow, Damage: 30

Let me know if I can clarify or explain something more in-depth.

Hey! This really helped! I have a couple of questions though :slight_smile:. Does the metatable act kind of like more information for an object? Like for example, a block has .Transparency, is that what a metatable is like? And I didn’t quite get _index. But for the rest, you have been so helpful! Thanks!

Yep this metatable stores the functions. __Index is used to allow individual objects to access the functions. Self is used as a variable to refer to the original object variables.

image

1 Like

You really should check out the documentation for metatables, but to answer your question shortly here, to do OOP in Lua, you have to use metatables, metatables are tables that can be attached to data, like normal tables, and make them more powerful.

__index is a metamethod, a metatable member, that can control how a table is indexed (like table["index"] or table.index). On normal tables, when you index a table, Lua first goes through the table, searching for the index, if it finds it, it returns the value attached to that index, if it doesn’t, then it checks if the table has a metatable attached to it, and if it has the __index metamethod set, if there’s an __index metamethod, it calls the __index metamethod with the index, so you can control whatever gets returned.

Here’s an example on how you can use it:

local tbl = setmetatable({}, {
  __index = function(t, i) -- This can also be just a reference to another table!
       return "hi" -- You can make a system here that returns whatever you want when the index cannot be found!
  end
})

print(tbl.hi) -- Since "hi" doesn't exist in the table, Lua calls the __index function we set, and the function returns "hi", so it will print "hi" here!

We use this in creating OOP mechanics, like the other person showed u above.

Check out the documentation from the link I’ve sent above for more information!

Now, let’s talk about what self is, self is essentially a pointer. But a pointer to what? You might ask, it’s essentially a pointer to an object.

Let’s go from some examples again:

(From @JamesBlossoms)

local Weapon = {}
Weapon.__index = Weapon

-- Constructor function
function Weapon:new(name, damage)
    local instance = setmetatable({}, Weapon)
    instance.name = name
    instance.damage = damage
    return instance
end

-- Method to display weapon details
function Weapon:display()
    print("Weapon: " .. self.name .. ", Damage: " .. self.damage)
end

Above example is a very simple OOP example weapon object, and you probably noticed that we have set the display() function with the : operator, and not the . operator, but why? The answer is simple, when you define a function using the : operator, the first argument to that function will always be the object itself, in this case it’s the weapon object, and since self is a pointer, whenever you use the : operator, self gets automatically defined under that function as a pointer to the first argument, which is our weapon object.

It might seem a little complicated at first, but it’s not that hard to grasp, and I advise you to check out some tutorials and documentation posts online.

Aside that, if you wish to make your OOP experience easier, I’ve recently created a module that makes class creation so much easier, you should definitely check it out, it removes the entire hassle of working with metatables.

1 Like

Thanks everyone! This helped me so much!

1 Like