Problems returning 'self' on client

I’m using a module script with a function to create a metatable with the variable self. I do this both on the client and server, the problem is that, once I print the return of the function on the server it returns the correct values but if I do it on the client it for some reason returns the functions within the module script.

function Framework:Initialize(WeaponName, Char)
	local Data = require(script.Support.WeaponData)[WeaponName]
	
	if RunService:IsClient() then
		local self = setmetatable({}, Framework)
		for i,v in pairs(Data) do
			self[i] = v
		end
		
		self.Character = Char
		self.Combo = 1
		self.Name = WeaponName
		print(self)
	else
		for i,v in pairs(Data) do
			self[i] = v
		end
		
		local Model = script.Assets[WeaponName].Weapon:Clone()
		Model.Parent = Char

		local BackWeld = Instance.new("Motor6D")
		BackWeld.Parent = Char.Torso
		BackWeld.Part0, BackWeld.Part1 = Char.Torso, Model.PrimaryPart
		BackWeld.C0 = Data["BackPos"] * Data["BackRotation"]
		BackWeld.Name = "WeaponWeld"
		BackWeld.C1 = CFrame.new(0,0,0)	
	end
	
        print(self)
	return self
end

Here’s the 4 prints
image
Print no.1 is done in the server (when I print self before returning self, this one works fine)

Print no. 2 is done on the client (the first time I print self, which returns the values I’m expecting)

As for print no.3 and no.4, they are ‘print(self)’ before the return on the module and once I attempt to print the return of the module on the client. Both of which return the functions within the module script
image

I really don’t get why on the client, it works the first time I print self, but on the second time I do it, it doesn’t work.

1 Like

I got it to work.

--...
if RunService:IsClient() then
		local self = setmetatable({}, Framework)
		for i,v in pairs(Data) do
			self[i] = v
		end
		
		self.Character = Char
		self.Combo = 1
		self.Name = WeaponName
		
		return self
--...

I returned self right after setting what self was supposed to be if the function was called on the client. This solved the problem, but I’d still love an explanation of why the last time it wasn’t working. I find self and module scripts in general really confusing

You’re doing two separate things on the client versus on the server.

Assuming you know that “self” is implicitly assigned as Framework in the scope of Framework:Initialize when you write “function Framework:Initialize(args)

On the client, you’re creating a new table called “self” in the scope of the if-statement whose metatable is framework. Because it’s in the scope of the if-statement, it isn’t what is being returned, so the function can’t “see” the new variable self. Think of it like this:

local a = 1
if true then -- this starts a new scope, the scope is visualized by the slashes at the beginning of each line
//// print(a) --> 1 because this scope can see everything in its "enclosing" scope, but the opposite is not true
//// local a = 2 -- think of "a" as a new variable that only the if-statement can see.
//// print(a)
end
-- so now, even though the previous if-statement was run, the scope ended so everything outside of the if-statement still sees "a" as 1
print(a) --> 1 because the variable "a" was never written to in this scope.

However, if we remove the local, it will write to the “enclosing” scope’s assignation of “a”

local a = 1
if true then -- again with the slashes to see the scope
//// print(a) --> 1
//// a = 2 -- now, we're writing to the real variable "a" that exists /outside/ of this scope
//// print(a) --> 2
end
print(a) --> 2 once again

I guess another way you can see it is like people who can only look at the next person/person ahead in line:

Think of not using “local” as a mirror

So back in your case, simply removing “local” from “local self” would reassign the variable “self” in the scope of your Framework:Initialize function and thus would give you what you’re expecting.


Now, on the server, you’re actually mutating/changing and writing to “self” instead of simply overwriting it which I think is what you should be doing on the client (which removing the local from local self would do once again).

Put the self variable above the if statement.
Like this:

local self = setmetatable({}, Framework)

if RunService:IsClient() then

Thanks for both of your answers! Can’t believe the solution was so simple…

1 Like

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