Is it possible to make smth like .Changed event NOT for Instances, but for numbers, strings, etc?

Hello, I’m start learning metatables. Now, I need add yielding function to my script, but it works with integers. Is it possible to create something with metatables like:

local Integer = 3
Integer.Changed:Wait()

?

I don’t believe there is any current function to check when a variable changes in a script except by using loops

I believe you can do:
repeat task.wait() until Integer ~= Integer

I am not 100% sure about this because I personally have never detected a change like linked up with a function but I think you can use __newindex(table, index, value) not sure. (just what I found when I looked around on google for the answer)

Okay, it is possible but you won’t be able to just make an int like
local Integer = 3
it would look more like:

local module = require(game.ReplicatedStorage.NumbersModule)
local Integer = module.new(3)

And you won’t be able to use .Changed but :Changed() instead (sorry only way I know)

Then in the ReplicatedStorage.NumbersModule module script you would need something like this:

local module = {}
module.__index = module

function module.new(val)
	local newVar = {}
	setmetatable(newVar, module)
	newVar.Value = val
	
	return newVar
end

function module:Changed()
	function self:Wait()
		local lastVal = self.Value
		repeat wait() until self.Value ~= lastVal
	end
	return self
end

return module

Then to test the script:

local module = require(game.ReplicatedStorage.NumbersModule)
local Integer = module.new(3)
task.spawn(function() -- This spawns a new thread so the wait won't halt script
	task.wait(5) -- Wait 10 seconds until we change the value
	Integer.Value = 10 -- Change the value
end)
Integer:Changed():Wait() -- Halt script
print("It's been 5 seconds") -- This prints after the value gets changed (we changed it after 5 seconds)

So yeah. This is the pretty close to what you want, as close as I can get you. Modules are pretty cool :sunglasses:

1 Like

Actual example:

local real = {}
local proxy = setmetatable({}, {
    __newindex = function(_, k, v)
      print('Key "'..k..'" changed to '..v)
      real[k] = v
    end,
})

proxy.number1 = 10
proxy.number2 = 20
print(real.number2)

Output:

Key "number1" changed to 10
Key "number2" changed to 20
20

And implementing a signal is straightforward:

local real = {}
local event = Instance.new('BindableEvent', script)
local proxy = setmetatable({}, {
	__newindex = function(_, k: any, v: any)		
		real[k] = v
		event:Fire(k)
	end,
})

event.Event:Connect(function(k: any)
	print('Value changed:', k, '->', real[k])
end)

--testing
proxy.number1 = 10
proxy[Vector3.new(1, 2, 3)] = CFrame.new(1, 2, 3)
proxy['yes'] = true
proxy.number1 = 20
proxy[Vector3.new(1, 2, 3)] = nil
proxy['yes'] = false

However it is recommended to use a native-Lua signal system such as GoodSignal for this kind of purpose

1 Like

made a module just for it

local module = {}

local function Value_Update(tab,k,v)
	getmetatable(tab):Fire(k,v)
end

function module:CreateMeta(t : table?)	
	local Bind = Instance.new("BindableEvent")
	
	return setmetatable(t or {}, {
		__index = {Changed = Bind.Event},
		__metatable = Bind,
		__newindex = Value_Update
	})
end

return module

1 Like

Ok so I went searching for a solution and found this post Adding a "Changed" event to a table, similar to an instance || Easy how-to guide

1 Like