Understanding LUA Callbacks - lua

For example this code:
-- Defining a function that takes a callback function as a parameter
function HelloMessage(callback)
-- Below you are passing the string "sup" as a parameter to the callback function
callback("sup")
end
-- Here, below, we are calling the function defined earlier
-- and we pass a callback function to it (a.k.a. "handler")
HelloMessage(function(message)
print(message) -- "sup" gets printed
end)
I did not understand how it works. How does it pass the sup into the message parameter??

HelloMessage(function(message) print(message) end)
is basically equivalent to
do
local callback = function(message) print(message) end
callback("sup")
end
which is equivalent to
do
local message = "sup"
print(message)
end
function(message) print(message) end defines an anonymous function that is immediately referenced by the function argument callback which is a local variable in HelloMessage's scope.

cb_function = function( var_txt ) print("var_txt = ", var_txt ) end
function HelloMessage( callback_func )
if type( callback_func ) == "function" then --just chek is func passed
callback_func( "Print to callback function" )
end
end
HelloMessage( cb_function ) --passing call back function

Related

Lua function returns string, but calling function gets nil

I'm writing a function for Nodemcu (esp8266) Lua to build command strings from UART (someone typing). When it finishes capturing characters, it's supposed to return the string to the calling function, but the calling function only gets nil. I'm new to Lua, What am I missing?
local function getcmd()
local t = { }
local cmd
-- Callback function
uart.on("data", 0, function(data)
if data~='\r' then
--Echo input
t[#t+1] = data
uart.write(0,t[#t])
-- BACKSPACE/DEL
if t[#t] == '' then
t[#t] = nil
t[#t] = nil
end
-- NEED <TAB> handling here too
else
--Disables callback
--uart.on("data")
-- Print table, convert to string.
for i = 1, #t do
uart.write(0, t[i])
if i==1 then
cmd = tostring(t[i])
else
cmd = cmd .. tostring(t[i])
end
end
t = { }
if cmd ~= nil then
uart.write(0, "Before Return> "..cmd)
-- type() String
return cmd
end
end
end,0)
end
local function config()
local cmdstr
-- Testing
cmdstr = getcmd()
print("func() "..getcmd())
if cmdstr ~= nil then
uart.write(0, cmdstr.."> ")
end
end
Thanks to #EgorSkriptunoff for helping me understand what was happening.
Below is the code that works (so far). What I tried was a While loop around the event handler inside of getcmd(). This fails because it stops execution of all the background events that keep things like wifi and other essential functions that keep the ESP8266 running, so it crashes/reboots repeatedly.
What I did instead of returning from getcmd() was call config() directly and pass it the input I collected in the event handler, like this: config(cmd)
The potential problem is, the event handler is still running since it never reached the end and that could cause some stack/memory issues if I don't return from config() before calling another function.
Anyway, here is the code that is working for the moment:
function getcmd()
local t = { }
cmd=nil
uart.on("data", 0, function(data)
if data~='\r' then
--Echo input
t[#t+1] = data
uart.write(0,t[#t])
-- BACKSPACE/DEL
if t[#t] == 'BS' then
t[#t] = nil
t[#t] = nil
end
else
--uart.on("data")
if #t ~= nil then
uart.write(0,"\r\n"..#t.."\r\n")
end
for i = 1, #t do
uart.write(0, t[i])
if i==1 then
cmd = tostring(t[i])
else
cmd = cmd .. tostring(t[i])
end
end
t = { }
if cmd ~= nil then
-- Calling config() here doesn't allow event handler on.uart() to end.
config(cmd)
end
end
end,0)
end
------------------------------------------------------
function config(cmd)
print("\r<<"..cmd..">>\r")
-- Now parse cmd and return.
end

Lua : return table trough function is nil

I get the error: source_file.lua:5: attempt to call a nil value (global 'getCard')
i try to catch the right table in questCards which Index=name is the same as the given string from objName
questCards={{['name']='test1',['creatureName']='test3'},{['name']='test2',['creatureName']='test4'}}
obj='test1'
card=getCard(obj)
card['creatureName']=nil --Only for test purpose
if card['creatureName']==nil then
--do Somthing
end
function getCard(objName)
for k,v in pairs(questCards) do
if v['name']==objName then
return v
end
end
end
The error message is telling you that getCard is not defined at the point where it is called.
You need to define getCard before calling it.

Meta table error

I am trying to set up a toy example for threading in torch but I am getting an error from running the code below. I think it might just be the way I set up the table but I am not sure.
Threads = require 'threads'
Threads.serialization('threads.sharedserialize')
DataThreads = {}
DataThreads.__index = DataThreads
local result = {}
local unpack = unpack and unpack or table.unpack
function DataThreads.new(nThreads,opt_)
local self = {}
opt_ = opt_ or {}
self.threads = Threads(nThreads,
function()
print("background stuff")
end
)
self.threads:synchronize()
-- The below for loop is causing the error but the same :addjob() works later on
for i=1, nThreads do
self.threads:addjob(self._getFromThreads, self._pushResult)
end
return setmetatable(self,DataThreads)
end
function DataThreads._getFromThreads()
x,y = torch.uniform(),torch.uniform()
return x,y
end
function DataThreads._pushResult(...)
local res = {...}
if res == nil then
self.threads:synchronize()
end
result[1] = res
end
function DataThreads:getBatch()
self.threads:addjob(self._getFromThreads, self._pushResult)
self.threads:dojob()
local res = result[1]
result[1] = nil
if torch.type(res) == 'table' then
return unpack(res)
end
print(type(res))
return res
end
d = DataThreads.new(4)
The error occurs in :addjob() in the .new function. However calling the same :addjob() later on in the :getBatch() function works. Am I not allowed to call the ._getFromThreads(), ._getFromThreads() functions before the metatable is set? Here is the error, which I think means ._getFromThreads() is not returning anything;
/home/msmith/torch/install/bin/luajit: ...e/msmith/torch/install/share/lua/5.1/threads/threads.lua:215: function callback expected
stack traceback:
[C]: in function 'assert'
...e/msmith/torch/install/share/lua/5.1/threads/threads.lua:215: in function 'addjob'
threads.lua:21: in function 'new'
threads.lua:54: in main chunk
When the code in your new function runs the metatable hasn't been set up yet so when you use self._getFromThreads and self._pushResult there's nothing there and you get nil back and that's not valid.
It works after the new function returns because at that point the metatable has been added so the lookups use the __index metamethod to look the entries up.
You can do
local self = setmetatable({}, DataThreads)
to set the metatable up immediately and then just
return self
at the end.

Scoping rules in Lua

I was testing the scope for Lua and noticed something unexpected. The following code does not print the localMainVariable.
function functionScope()
print( "\nIn function")
print( "globalMainVariable: " .. globalMainVariable )
if (localMainVariable ~= nil) then print( "localMainVariable: " .. localMainVariable ) end
end
globalMainVariable = "Visible"
local localMainVariable = "Visible"
functionScope()
But the following code does print localMainVariable.
globalMainVariable = "Visible"
local localMainVariable = "Visible"
function functionScope()
print( "\nIn function")
print( "globalMainVariable: " .. globalMainVariable )
if (localMainVariable ~= nil) then print( "localMainVariable: " .. localMainVariable ) end
end
functionScope()
I know it has something to do with where the localMainVariable was declared, but I thought making it local would limit the scope of the variable. What is the actual rule?
Thanks
The scope of a local variable begins at the first statement after its
declaration and lasts until the last non-void statement of the
innermost block that includes the declaration.
Lua manual

attempt to index local 'self' using MOAICoroutine in Lua

I am just starting with MOAI and I am trying to create a traditional game loop using MOAICoroutine. The problem is that when I pass it the function that is part of a "class" that is built using 30log, it returns an error. It seems to continue to function, but I would like to fix the error. My guess is that the MOAICoroutine is calling the function using the dot notation rather than the syntactical sugar method with a colon. Here is the code:
class = require "30log.30log"
GameSystem = class ()
function GameSystem:__init(Name, Title)
self.Name = Name
self.Title = Title
self.Ready = false
end
function GameSystem:Run()
if self:Init() then
self.Thread = MOAICoroutine.new ()
self.Thread:run(self.Start)
--self:Start()
return true
else
print("Init failed.")
return false
end
end
function GameSystem:Init()
print("Initializing Game System")
if not self:InitTimer() then return false end
if not self:InitWindow(640,480) then return false end
if not self:InitViewport() then return false end
if not self:InitGraphics() then return false end
if not self:InitSound() then return false end
if not self:InitInput() then return false end
self.Ready = true
return true
end
function GameSystem:Start()
print("Starting Game System")
while self.Ready do
self:UpdateTimer()
self:UpdateGraphics()
self:UpdateSound()
self:UpdateInput()
coroutine.yield()
end
end
function GameSystem:InitTimer()
return true
end
function GameSystem:InitWindow(width, height)
print("Initializing Window")
return true
end
function GameSystem:InitViewport()
print("Initializing Viewport")
return true
end
function GameSystem:InitGraphics()
print("Initializing Graphics")
return true
end
function GameSystem:InitSound()
print("Initializing Sound")
return true
end
function GameSystem:InitInput()
print("Initializing Input")
return true
end
function GameSystem:UpdateTimer()
--print("Updating Timer")
return true
end
function GameSystem:UpdateGraphics()
--print("Updating Graphics")
return true
end
function GameSystem:UpdateSound()
--print("Updating Sound")
return true
end
function GameSystem:UpdateInput()
--print("Updating Input")
return true
end
Is the 30log class code causing this problem? I have tried various things. I am pretty sure the self it is trying to access is the first argument i.e. mytable.myfunction(self, myarg). Any ideas to fix this nil value reference. The error actually occurred on the second line inside the Start function (while self.Ready do).
function GameSystem:Run()
if self:Init() then
self.Thread = MOAICoroutine.new ()
self.Thread:run(self.Start)
My guess is that the MOAICoroutine is calling the function using the dot notation rather than the syntactical sugar method with a colon.
How would it be calling the function using dot notion (or colon notation)? What would be on the left side of the period or colon? You haven't passed it an object, only a function. The fact that it's caller was storing that function in a table is completely unknown to it. It just receives a function, and calls it.
If you want your coroutine to start with a method call, do that in the function you pass to coroutine.start:
self.Thread = MOAICoroutine.new ()
self.Thread:run(function() self:Start() end)
The point is that:
function GameSystem:Start()
end
Is exactly equivalent to:
function GameSystem.Start(self)
end
Is exactly equivalent to:
GameSystem.Start = function(self)
end
Is equivalent to:
function Foobar(self)
end
GameSystem.Start = Foobar
If I call:
print(Foobar)
print(GameSystem.Start)
print(someGameSystemInstance.Start)
print receives the same value. In Lua, a function is a function is a function, it's not "tainted" in some way by being stored in a table, such that a third party with a reference to the function can know that you want it to be called as a method to some particular 'class instance.

Resources