Can anyone explain what "self" does in this script and how it works?

Hi DevForum,

I just had a question about “self”, and setting the __index metamethod of a table equal to that table itself.

local class = {}
class.__index = class

function class.new()
	local self = setmetatable({2}, class)
	
	return self
end

function class:Something()
	print(self)
end

local c = class.new()

c:selfSomething()

For example, for this line I know that the self variable (used in “print(self)”) is equal to the table passed by setmetatable():

local self = setmetatable({2}, class)

I am just confused on how it all works together, moreso why it works, mainly on these lines:

class.__index = class
c:selfSomething()

(I know this question was asked a few times, I was just looking for a more simple explanation that makes sense to me)

2 Likes

Object-oriented programming (OOP) can be confusing; Although I use it, __index and metatables are just plain confusing, even to me. From what I know, __index is one of the “metamethods” in a table’s metatable, which stores info about its contents, such as its variables and any tables nested within it.

In your example, outside of the .new() constructor, you’re defining the “base class”, which contains all of the class’ functions and variables. Here, __index’s contents matches what the table contains, since they’re one and the same.

However, in class.new(), a brand new table is created (which you already know). This new table is empty, but it uses setmetatable() to set the new table’s metatable to the original class’s one, and since its __index metamethod was set to the class’s contents, it will check that table if it can’t find something in the new object’s table.

c:Something() works because you linked the new table to the original using its metatable; When you call that function, Roblox sees if the new object contains c.Something. If the metatable wasn’t set, this would produce an error, but Roblox checks the table stored in __index, finds Something() there, and executes that instead.

:wink: If you defined a new function in the .new() constructor with the same name, Roblox would use that instead of falling back on the class’s own. Interestingly, this is how programmers make classes that “inherit” from each other, which is too confusing for me…

Info about calling functions using colons and periods...

I know you didn’t ask about this, but I wanted to add that functions called using a colon (like c:Something()) call the function with a reference to the object as its first parameter (as the variable “self”). So, class.Something(c) should do the same thing.

:angst: I hope this wasn’t too confusing and was useful; My mind can’t write as well-written sentences as it used to, but I wanted to explain what I knew about that metamethod and OOP.

1 Like

When you use the word “self” within the constructor (class.new()), it is only being used as a variable name and could be named anything else. When you use the word self in a method like class:Something(), self refers to the table that method is bound to.

local class = {}
class.__index = class

function class.new()
	local self = setmetatable({2}, class)
	
    self.Value = 123

	return self
end

function class:Something()
	print(self.Value) -- prints 123
end

local c = class.new()

c:Something()

You can also use self in methods for regular tables, so long as they are using : and not . and it will represent the table the method you are using is bound to.

local Module = {
     Value = 1234,
}

function Module:DoSomething()
    print(self.Value) -- prints 1234
end

There may not be a need for self, depending on how you structure your code.

This video below gives a good explanation of object oriented programming, as well as a way to achieve similar results by using a different method
https://www.youtube.com/watch?v=-E_L6-Yo8yQ

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.