Can anyone explain this code to me?

Hello devforum,

I would like to start off by saying this is not my code I found it here, the creator of this post is whom I assume it belongs to. The way the code works is when required by a script then calling the object it will call the __init function and make these event_listeners for events in-game. I just want someone to explain what these lines of code do self[method](self, ...), self[method](self)

script(a basic script that requires the server module and creates the event listeners.)

local server = require(game.ServerStorage.Server)
local newServer = server()


local Rcade = require(game.ServerStorage.Rcade) 
local Server = Rcade.class{}

function Server:__init()
	Rcade.Utility.eventListener(self, game.Players.PlayerAdded, "onJoin")
	Rcade.Utility.eventListener(self, game.Players.PlayerRemoving, "onLeave")
	Rcade.Utility.bindToClose(self, "onClose")

function Server:__tostring()
	return "Server"

function Server:onJoin(player)
	print(player.Name .. " joined")

function Server:onLeave(player)
	print(player.Name .. " left")

function Server:onClose()
	print("The server is closing")

return Server

utility_module(handles the event listener stuff that I am curious about.)

local Utility = {}
local RunService = game:GetService("RunService")

function Utility:eventListener(bindableEvent, method)
		self[method](self, ...)

function Utility:remoteListener(remoteEvent, method)
	if RunService:IsServer() then
			self[method](self, ...)
	elseif RunService:IsClient() then
			self[method](self, ...)

function Utility:bindToClose(method)

return Utility

eventListener accepts three arguments: self (implicitly passed when called with a colon), an RBXScriptSignal and a method name to call. The way the methods get called is that it’ll look for the third argument as an index of the first argument when the second argument is fired.

When eventListener is called with dot syntax, self isn’t implicitly defined to the function’s scope so that’s a free parameter for the developer. In Server:__init, self refers to Server. eventListener is called with dot syntax so that Utility isn’t passed instead and the developer instead passes Server, PlayerAdded (for the first signal) and onJoin as the method to be called.

When PlayerAdded fires, it will look for onJoin in the self table (which is Server). As indexing with brackets does not give a chance to implicitly pass self, the developer simulates colon calling by passing self again and any arguments that were given to the RBXScriptConnection by the caller.

Therefore, reiterating, eventListener:

  • Takes a table, an RBXScriptSignal and a string of what to look for

  • When the RBXScriptConnection is fired (created by Connect to the RBXScriptSignal), it’ll look in the table for the string

  • Assuming table[value] == function:

    • It is called with self again. Since methods in Server are defined with self but the method isn’t called with colon syntax, the script needs to know what self is going to be.

    • … is passed after self. This is variable arguments, arguments fired to the RBXScriptConnection are forwarded to the aforementioned function.

Server’s __init calls eventListener in its raw form without any implicit definitions.

It may be easier for you to understand and visualise what’s going on if you replace every instance of colon with a dot instead and prefix every parameter list with “class” (or something more suitable) instead since that way you can explicitly see the mapping of arguments. The involvement of self and the implications of defining functions a certain way are probably where your confusion roots from. Example for eventListener:

function Utility.eventListener(self, bindableEvent, method)
    -- Rest of code here

I understand the difference between the colon and the dot operator. And how colon will automatically pass self etc. I was just confused that I didn’t think the player added event would go into this script and go through the modules and run the code but thanks this did help me a lot.