Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lua event handler

Tags:

lua

Does lua have an "event handler" build in or does it have a lib available to do that?

So that, an example, when "a = 100" an event happens.

Something else rather than using:

while true do
 if a == 100 then
   [...]
   break;
 end
end

Or simply adding a sleep to it. The "while true do" is just an example but its a terrible one.

like image 813
luacoder Avatar asked Nov 29 '11 02:11

luacoder


1 Answers

Lua operates in a single-thread, so any checking must be explicitly performed by your code.

The act of performing code immediately upon a variable changing is known as "watching".

If you are programming in an environment where a set of code is run every frame (such as a game), you can check manually. For example:

WatchedVariables = {
    a = 5,
    b = 22,
}
WatchedVariables_cache = {}
for k,v in pairs(WatchedVariables) do
    WatchedVariables_cache[k] = v
end

function OnFrame()
    print("NEXT FRAME! (possibly 1 second later or something)")
    for k,v in pairs(WatchedVariables) do
        local v_old = WatchedVariables_cache[k]
        if v ~= v_old then
            -- this is the "callback"
            print(tostring(k).." changed from "..tostring(v_old).." to "..tostring(v))

            WatchedVariables_cache[k] = v
        end
     end
 end

 function SomeFunctionThatOperatesSomeTime()
     print("about to change a, brother!")
     WatchedVariables.a = -7
     print("a is changed")
 end

Upon the next frame, the callback code (the print) will be executed. The disadvantage of this approach is that the callback code is not printed immediately after WatchedVariables.a is set to -7, that is: the output will be:

about to change a, brother!
a is changed
NEXT FRAME! (possibly 1 second later or something)
a changed from 5 to -7

To prevent this potentially undesired behaviour, a setter function can be used, for example:

MyObject = {
    _private_a = 5,
    set_a = function(self, new_value_of_a)
        self._private_a = 5
        -- callback code
        print("a set to "..tostring(new_value_of_a))
    end,
    get_a = function(self)
        return self._private_a
    end
}

function SomeFunctionThatOperatesSomeTime()
     print("about to change a, brother!")
     MyObject:set_a(-7)
     print("a is changed")
 end

The output of this code shows that the callback runs immediately:

about to change a, brother!
a set to -7
a is changed

To make this more comfortable, Lua provides metatables that make such behaviour transparent to the programmer. Example:

MyObject = {
    __privates = {
        a = 5,
    }
}
MyObject_meta = {
    __index = function(self, k)
        return rawget(self, "__privates")[k]
    end,
    __newindex = function(self, k, v)
        rawget(self, "__privates")[k] = v
        -- callback code
        print("a set to "..tostring(v))
    end,
}
setmetatable(MyObject, MyObject_meta)

function SomeFunctionThatOperatesSomeTime()
     print("about to change a, brother!")
     MyObject.a = -7
     print("a is changed")
 end

The output of this code will be the same as the previous example:

about to change a, brother!
a set to -7
a is changed

Here's an implementation for your example case:

MyObject = {
    __privates = {
        a = 5,
    }
    __private_callback = function(self, k, ov, v)
        if k == "a" and v == "100" then
            print("a is 100!")
        end
    end
}
MyObject_meta = {
    __index = function(self, k)
        return rawget(self, "__privates")[k]
    end,
    __newindex = function(self, k, v)
        local privates = rawget(self, "__privates")
        local ov = privates[k]
        privates[k] = v
        rawget(self, "__private_callback")(self, k, ov, v)
    end,
}
setmetatable(MyObject, MyObject_meta)

function SomeFunctionThatOperatesSomeTime()
     MyObject.a = -7 -- prints nothing
     MyObject.a = 100 -- prints "a is 100!"
     MyObject.a = 22 -- prints nothing
 end

Why are the variables __privates and __private_callback prefixed with two underscores? It is convention to prefix private members that should not be accessed in typical programming situations with two underscores. If you familiar with object-oriented methodology and it's implementation in languages such as Java and C++, you will understand how it is similar to the private and protected keywords.

If you are familiar with the C# language, you may see how the set_a/get_a and metatable implementations are similar to accessors (set/get).

like image 176
Deco Avatar answered Nov 10 '22 14:11

Deco