Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

How to detect if a variable changes?

Lets say I have a variable

local var = 0

And a function

function updateText(text)
	TextLabel.Text = text
end

Then I change the variable.

var = 35

How do I run the function updateText(var) when the variable changes? The variable will have to work for every value type (including tables).

I have thought of a few methods of doing this but some are pretty hacky. I would prefer to do this just inside the script and not using any roblox provided objects if possible

METHOD 1: Whenever I change the variable fire the function.

Aww that's no fun. I would like to not have to type that out everytime

METHOD 2: Fire a remoteEvent with an argument of what we want to change the variable to, then (assuming this is client side), in the serverside using the OnServerEvent event fire the remoteEvent again, in client side using the OnClientEvent event run the function and change the variable to the argument that we provided

Uh, hacky and we need to wait for Server and Client communications to happen and that will only work if we have a player in the game and it is client side.

METHOD 3: Use a value object and use the Changed event

What about table variables

Any help would be appreciated

3 comments

0

Perhaps a Value object?

0

Oh I forgot to write that method in, thanks for reminding me. But I really would like to use only Lua for this

0

Edited

2 answers

✓ Accepted answer

There isn't a direct way to watch a variable change.

This is mostly to make Lua understandable -- when you change a variable, only that variable changes.

You can still accomplish this, though. First: there is a reason you cannot do extra work when dealing simply with variable. It makes Lua easier to understand when you play by the normal rules. ROBLOX cheats all over the place with Lua's rules; if you think about it, you can probably come up with lots of different places where it cheats. That doesn't mean you should!

Getters and Setters

An idiomatic solution is getters and setters. Instead of using a variable directly, you use two functions. This lets you react to changes. For instance, we can limit a number to be between 0 and 1:

do 
	local x = 0
	-- local in a do means no one can directly use `x`
	-- EXCEPT by getX and setX
	-- (if you trust yourself to not use `x`, the `do/end` is unnecessary)

	function getX()
		return x
	end

	function setX(newX)
		if newX > 1 then
			x = 1
		elseif newX < 0 then
			x = 0
		else
			x = newX
		end
	end
end

setX(2)
print(getX()) -- 1

setX(0.5)
print(getX()) -- 0.5

Polling

An often sufficient method is to just repeatedly ask. If, for instance, you just need to show a value on the screen, this is probably enough:

while wait() do
	script.Parent.Text = value
end

If you want to do it in the background, you can spawn a new thread to do that.

Metatables

Lua has a feature called metatables. These redefine the way that basic operations work in Lua.

Using the __index and __newindex metamethods, we can take advantage of the getter and setter pattern, but make it look like property of an object (this is more or less how .Changed is implemented in ROBLOX objects)

It looks like this:

local t = {}
local value
function get(obj, property)
	assert(property == "value") -- only allow `t.value` to be gotten
	return value
end

function set(obj, property, newValue)
	assert(property == "value") -- only allow `t.value` to be set
	if newValue > 1 then
		value = 1
	elseif newValue < 0 then
		value = 0
	else
		value = newValue
	end
	-- (Do whatever extra stuff here)
end

setmetatable(t, {__index = get, __newindex = set} )

t.value = 5
print(t.value) -- 1
t.value = 0.5
print(t.value) -- 0.5

Metamethod + Environment Hack

Pure Lua 5.1 will let you do this more directly. Diito's answer tells you how to get this to work in ROBLOX.

First: do not do this. To an even greater extent than the above, it can be incredibly confusing and frustrating.


Global variables (as opposed to local, not those in _G -- although in vanilla Lua this is essentially the same) are actually properties stored in a table. That table is called the environment, and you can give it a metatable.

Applying the previous lets you do getters and setters on plain variables -- horrifying!

setmetatable( getfenv(), {__index = get, __newindex = set} ) -- get and set from before

value = 1
print(value) -- 1

value = -1.5
print(value) -- 0 ???

value = 0.5
print(value) -- 0.5

2 comments

0

Thank you for answering, I haven't really found a reason to learn metatables but I guess they are useful for something after all! PS: Line 16 of the last code block

0

getters and setters is usually the better approach because it's clearer and simpler, though slightly less compact.

Following up BlueTaslem... Metamethod + Environment Hack [in a correct way if pro] :

local Environment = getfenv(1)
local Metatable = {}
Metatable.__index = {}
Metatable.__metatable = "This metatable is locked"

function Metatable:__newindex(self, index, value)
	Metatable.__index[index] = value
	updateText()
end

setfenv(1, setmetatable({}, Metatable))

2 comments

0

Oh, setfenv is unlocked! I totally forgot about that

0

(Still: don't do this!)

This discussion is preserved as it was. New answers, comments, and votes are closed.