Self doesn't refer to the object that calls it?

very beginner self user here, i am very confused
self refers to the object that calls the function, so why does mine refer to the name of the function??

image


i call the function from a for loop:

for _,button in buttons:GetChildren() do
	if button:IsA("ImageButton") then
		button.Activated:Connect(function()
			mainMenuModule:OnButtonClicked(camera, plr)
		end)

		button.MouseEnter:Connect(function()
			OnButtonHoverEnter(button)
		end)

		button.MouseLeave:Connect(function()
			OnButtonHoverLeave(button)
		end)
	end
end

and i receive it from a module that’s inside replicated storage

function menuModule:OnButtonClicked(camera: Camera, plr: Player)
	print(self)
	-- these 2 variables are so stupid i hate them
	local mainMenu: ScreenGui = self.Parent.Parent
	local blink: Frame = mainMenu.Blink

	blink.Visible = true
	
	local tweenGoal = {BackgroundTransparency = 1}
	local blinkTween = tService:Create(blink, blinkTweenParams, tweenGoal)
	
	blinkTween:Play()
	buttonEffects[self.Name](self, camera, plr)
	blinkTween.Completed:Wait()
	
	blinkTween:Destroy()
	blink.Visible = false
end
1 Like

It’s referring to a table that has a key “OnButtonClicked” whose value is a function. That looks to be your menuModule, no?

1 Like

well yeah, but, the imagebutton is what calls the function, so shouldn’t self be the imagebutton??

1 Like

Nope, the method caller is

--v this guy v--
mainMenuModule:OnButtonClicked(camera, plr)

If you want to access the image button in that method, you’ll have to pass it as an argument to the method.

2 Likes

hii its me again



so im just going to explain a general bit of self here.
In all basic terms, the purpose of self is to point to the table that calls the function.



So, you know how you can call something in two ways, with a colon and with a dot? There’s a slight difference - the colon passes the thing itself as a parameter.

local test = {
    test = function(self) print(self) end
}

test.test() --> nil, nothing was passed to self
test:test() --> prints out table test because the table was passed as a parameter
test.test(test) --> equivalent to test:test()
test.test(3) --> 3

So, after looking over that example, you might be asking “How come the last example prints out 3 instead of the table?” Well, no matter what, self will always just be the first parameter passed to the function, as you can see when we define it with it as the first parameter. The same thing goes for defining functions with colon notation:

local test = {}
function test:test()
    print(self) --> implicitely defined with colon notation
end

test.test() --> nil, nothing to go into self
test:test() --> prints table test
test.test(test) --> equivalent to test:test()
test.test(3) --> 3

Ok, but now you might be getting a bit more confused, because in Roblox OOP you see people defining self with the local keyword! what?!

function Class.new()
    local self = setmetatable({}, Class)
    --...
end

Well, this is really going to throw you for one…

because in other programming, self is used to refer to the object itself. So, you could say it’s similar, because in Lua, it points to the table itself. So, people use the proper variable to create objects, note how the new function is defined with a . so it doesn’t mess with implicit defining of self.

Here’s a post that probably explains it better than I do:
What is self and how can I use it? - Help and Feedback / Scripting Support - Developer Forum | Roblox

again if you have questions fire away

1 Like

british goat…

if self points to the table that calls the function, how on earth can i even use it?
if i use it in a module script, i will ALWAYS get the name of the table, instead of the object that calls the function (a tool, for example)

1 Like

yeah I don’t think you really need to use self here. You’d need to pass it as a separate parameter like @tyzone said. self is only really needed when a table needs to reference itself within a function, so like if you put this:

local a = {
    b = function(self)
        --try to reference a here
    end
}

you’ll get a lint warning saying that a is unknown global i.e. it’s not defined.

So, unless you need to reference menuModule in OnButtonClicked, there’s basically no use for self here. Even then, you can reference it directly from within the module.

2 Likes

You’re conflating two different concepts: the owner of a member function, and the caller of a function. This is a common misunderstanding, since it’s actually really commonplace for OOP code to call their own member functions from within other member functions, using self:someMemberFunction(), in which case the caller and the function owner are the same object.

For your example of line mainMenuModule:OnButtonClicked(camera, plr):

The member function ‘OnButtonClicked’ belongs to the mainMenuModule object. Inside the member function that is called with the colon : syntax, self refers to the mainMenuModule object. (This is a bit oversimplified, because in typical Lua OOP patterns, the mainMenuModule might not actually define ‘OnButtonClicked’, it could inherit from another table (a base class) via its metatable.)

The caller of OnButtonClicked is not shown to us in your code snippet. It’s depends on what the context is of this for loop, which we cannot see.

What we do know is that an ImageButton is neither A. the caller of OnButtonClicked() nor B. the owner. We know A because we can see that button is just a locally-scoped loop variable, in some script or function whose scope we can’t see. We know B because your syntax is calling a member function of whatever mainMenuModule is, and that is not the ImageButton. ImageButtons are also a Roblox UserData object and don’t have an OnButtonClicked function.

Your code is probably close to what you want, except you probably want the function call to close over button as an upvalue, like so:

mainMenuModule:OnButtonClicked(button,camera, plr)

And within the function, the button parameter is used where you’re currently mistakenly using self (which refers to the mainMenuModule)

1 Like