Connect functions with parameters?

I want to call functions when specific variables changed, but I would rather have it so one single function is called when variables change, with the variable name that changed transfered through parameters.

To explain it better using examples, would it be possible to turn this right here:

leaderstats.Strength.Changed.Connect:(strengthChanged)
leaderstats.Defense.Changed.Connect:(defenseChanged)

local function strengthChanged()
	print("Strength has changed")
end

local function defenseChanged()
        print("Defense has changed")
end

into something like:

leaderstats.Strength.Changed.Connect:(variableChanged("Strength"))
leaderstats.Defense.Changed.Connect:(variableChanged("Defense"))

local function variableChanged(varName)
        print(varName .. "has changed")
end

I tried using the second option in another context, but it didn’t work for some reason.

5 Likes

It didn’t work because you did

leaderstats.Strength.Changed.Connect

Instead, you should have done

leaderstats.Strength.Changed:Connect

Connect functions only work with a colon and you were using a “.” the first time which is probably why it didn’t work

Also, after the Connect, you put another colon, which wouldn’t work either. Here is the updated line of code:

leaderstats.Defense.Changed:Connect(variableChanged("Defense"))
local function variableChanged(varName)
        print(varName .. "has changed")
end

leaderstats.Strength.Changed:Connect(variableChanged("Strength"))
leaderstats.Defense.Changed:Connect(variableChanged("Defense"))

The functions need to be defined prior to you attempting to call them, I’ve also changed your Connect event so now it should work.

Yes, you are right, but after the Connect, you put another colon, which is unneeded and will give an error.

The proper I believe it has to be done is

local function variableChanged(varName)
    print(varName .. "has changed")
end

leaderstats.Strength.Changed:Connect(function()
    variableChanged("Strength")
end)
leaderstats.Defense.Changed:Connect(function()
    variableChanged("Defense")
end)

From what I can remember, you can’t do it like that because it will give the error “Passed value is not a function”, because you can only pass in the function by the name only, so variableChanged, but you want to pass a specific parameter, so you have to create a function and in there, call the custom function

23 Likes

Thanks, that fixed it.

But is there no better way to do this?
Calling a function to call another function seems kind of unpractical.

4 Likes

Sadly from what I believe there isn’t really a way to optimize it a bit from what I can tell without having to complicate things, this is the only real way to do what you wanted without making anything complicated to understand in the long run

10 Likes

Have you confirmed that this code works yourself? I promise you it doesn’t. RBXScriptSignal:Connect accepts only one argument: a callback function reference. Additional arguments are not forwarded to the callback at the time of the event, they’re simply dropped. This behaviour is observed in some API members though, like pcall and task.spawn/delay.

As @EmbatTheHybrid demonstrated, the only viable solution is to create a delegate callback which calls your function with the additional arguments. You can simplify your code by making a variadic function factory, however:

local function callsWith(callback: (...any) -> any, ...): (...any) -> any
	local additional = {...}
	
	return function(...)
		local arguments = {...}
		
		table.move(additional, 1, #additional, #arguments + 1, arguments)
		
		return callback(table.unpack(arguments))
	end
end
local function x(...)
    print(...)
end

local y = callsWith(x, "Hello,", "world!")
y(1, 2, 3) --> 1    2    3    Hello,    world!
local function onChanged(newValue, name)
    print(newValue, name)
end

strength.Changed:Connect(callsWith(onChanged, "Strength"))
defense.Changed:Connect(callsWith(onChanged, "Defense"))
2 Likes