Table continues to exist, even if I set it to nil or used table.clear()

I tried to make a spring motion effect (written in a module) for my UI.

module.Spring = function(Object, To, Time : number?) -- Similar to Elastic, but with a linear "progression?"
	local CurrentTime = 0
	local TargetTime = Time or 1
	
	local Connection = nil
	
	local Functions
	
	Functions = {Cancel = function()
		Update(Object, To)
		Connection:Disconnect()
	end}
	
	local Filtered = {}
	local Original = {}
	local DistanceFromTarget = {}
	
	for k, v in pairs(To) do
		local Valid = TestPropertyValid(Object, k)
		local ValidType = TestPropertyType(v)
		
		if Valid and ValidType then
			Filtered[k] = v
			Original[k] = Object[k]
		end
	end
	
	Connection = RunService.RenderStepped:Connect(function(step)
		CurrentTime += step
		if CurrentTime >= TargetTime then
			Functions.Cancel()
			table.clear(Functions)
			Functions = nil
			return
		end
		
		local Sine = (math.sin(((CurrentTime / TargetTime) * math.pi) * 15))
		local LerpAlpha = ((CurrentTime / TargetTime))
		
		Sine = Sine + (1 - Sine) * LerpAlpha
		
		local NewStep = {}
		
		for k, v in pairs(Filtered) do
			if typeof(v) == "UDim2" then
				--[[
				local Old : UDim2 = (v - Original[k])
				print(Sine)
				local XS = Old.X.Scale * Sine
				local XO = Old.X.Offset * Sine
				local YS = Old.Y.Scale * Sine
				local YO = Old.Y.Offset * Sine
				
				NewStep[k] = Original[k] + UDim2.new(XS, XO, YS, YO)]]
				print(Sine)
				NewStep[k] = Original[k]:Lerp(v, Sine)
				continue
			end
			NewStep[k] = Original[k] + (v - Original[k]) * Sine
		end
		
		Update(Object, NewStep)
	end)
	
	return Functions
end

I basically made the module function return a table of functions (well… actually just one for now, which “cancels” the tween.) when module.Spring() is called. In my other script…

if IsDisabled == true then
		local ExTween_Funcs
		Button.BackgroundColor3 = Color3.fromRGB(220, 220, 220)
		Button.MouseButton1Click:Connect(function()
			local RejectAnimationBuildup = TweenService:Create(Button, Main_Menu_Button_Click_Info, Main_Menu_Button_Disabled.Button)
			--local RejectAnimationRelief = TweenService:Create(Button, General_Button_Disabled_Info, Main_Menu_Button_DefaultNoColor.Button)

			SoundSystem.PlayOnce("Disabled")
			if ExTween_Funcs then
				ExTween_Funcs.Cancel()
				ExTween_Funcs = nil
			end
			RejectAnimationBuildup:Play()
			wait(0.1)
			ExTween_Funcs = ExtraTweens.Spring(Button, Main_Menu_Button_DefaultNoColor.Button, .4)
			--RejectAnimationRelief:Play()
		end)
		return
	else
		-- blah blah blah

The local variable ExTween_Funcs gets that table. Once the tween finishes or I call the Cancel function, I would make the variable nil, or the tween module will make it nil. Regardless, the ExTween_Funcs variable still holds the now-empty table, and it causes this error:

Players.Y_VRN.PlayerGui.ScreenGui.Main.Essentials.Interface:147: attempt to call a nil value
02:00:45.454 Stack Begin
02:00:45.455 Script ‘Players.Y_VRN.PlayerGui.ScreenGui.Main.Essentials.Interface’, Line 147
02:00:45.456 Stack End

I’m not sure why this happens. Earlier, I tried to make the Cancel function clear the table Functions through table.clear() and table = nil, but neither worked. Even tried to put the same methods on the RenderStepped function when it finishes, and on the other script too, yet to no avail.

How do I fix this, and why does this even happen to begin with?

table.clear() just removes everything from the table. Check if the number of a table is greater than 0.

			if #ExTween_Funcs > 0 then
				ExTween_Funcs.Cancel()
				ExTween_Funcs = nil
			end

OR, alternatively, check if cancel is even a thing.

			if ExTween_Funcs.Cancel then
				ExTween_Funcs.Cancel()
				ExTween_Funcs = nil
			end

Neither would work. Counting an array does give me what is expected, but counting a dictionary tells me a different story. Also, the variable ExTween_Funcs is set to nil. Only when the script detects that it is nil will it call module.Spring, then ExTween_Funcs will be a table value, so calling the function Cancel throws an error that the variable is nil.

Atable = {}
Atable = nil
table.clear(Atable)

Other than those methods, you can’t really remove a table’s existence, but you can always overwrite the table. I’m sure there’s a way for you to do that.

There’s more information provided in this similar post:

Finally realized the problem once I read the topic you attached, and it was rather simple. Thanks!

For those who are wondering, the ExTween_Funcs still holds a reference to the same table, instead of actually becoming nil once my Tween module does it first. All I had to do is check if the variable is a table (the first time the function is run after clicking a button), then if it’s true, then check if the Cancel function exists and if it’s true also, just run the function. After that, nullify the table to be garbage collected.

Fix (Tween module)

if typeof(ExTween_Funcs) == "table" then
	if ExTween_Funcs.Cancel ~= nil then
		ExTween_Funcs.Cancel()
	end
	ExTween_Funcs = nil
end
1 Like