Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
5

How to detect if a variable changes?

Asked by 9 years ago

Lets say I have a variable

1local var = 0

And a function

1function updateText(text)
2    TextLabel.Text = text
3end

Then I change the variable.

1var = 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

0
Perhaps a Value object? funyun 958 — 9y
0
Oh I forgot to write that method in, thanks for reminding me. But I really would like to use only Lua for this YellowoTide 1992 — 9y
0
Edited YellowoTide 1992 — 9y

2 answers

Log in to vote
7
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
9 years ago

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:

01do
02    local x = 0
03    -- local in a do means no one can directly use `x`
04    -- EXCEPT by getX and setX
05    -- (if you trust yourself to not use `x`, the `do/end` is unnecessary)
06 
07    function getX()
08        return x
09    end
10 
11    function setX(newX)
12        if newX > 1 then
13            x = 1
14        elseif newX < 0 then
15            x = 0
View all 26 lines...

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:

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

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:

01local t = {}
02local value
03function get(obj, property)
04    assert(property == "value") -- only allow `t.value` to be gotten
05    return value
06end
07 
08function set(obj, property, newValue)
09    assert(property == "value") -- only allow `t.value` to be set
10    if newValue > 1 then
11        value = 1
12    elseif newValue < 0 then
13        value = 0
14    else
15        value = newValue
View all 25 lines...

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!

01setmetatable( getfenv(), {__index = get, __newindex = set} ) -- get and set from before
02 
03value = 1
04print(value) -- 1
05 
06value = -1.5
07print(value) -- 0 ???
08 
09value = 0.5
10print(value) -- 0.5
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 YellowoTide 1992 — 9y
0
getters and setters is usually the better approach because it's clearer and simpler, though slightly less compact. BlueTaslem 18071 — 9y
Ad
Log in to vote
3
Answered by
Diitto 230 Moderation Voter
9 years ago

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

01local Environment = getfenv(1)
02local Metatable = {}
03Metatable.__index = {}
04Metatable.__metatable = "This metatable is locked"
05 
06function Metatable:__newindex(self, index, value)
07    Metatable.__index[index] = value
08    updateText()
09end
10 
11setfenv(1, setmetatable({}, Metatable))
0
Oh, setfenv is unlocked! I totally forgot about that BlueTaslem 18071 — 9y
0
(Still: don't do this!) BlueTaslem 18071 — 9y

Answer this question