Lua : Dynamically calling a function with arguments
-
19-09-2019 - |
Question
Using Lua, I'm trying to dynamically call a function with parameters. I want to send a string to be parsed in a way that:
- 1st argument is a class instance "Handle"
- 2nd is the function to be called
- All that is left are arguments
"modules" is a a table like { string=<instance of a class> }
split() is a simple parser that returns a table with indexed strings.
function Dynamic(msg)
local args = split(msg, " ")
module = args[1]
table.remove(args, 1)
if module then
module = modules[module]
command = args[1]
table.remove(args, 1)
if command then
if not args then
module[command]()
else
module[command](unpack(args)) -- Reference 1
end
else
-- Function doesnt exist
end
else
-- Module doesnt exist
end
end
When I try this with "ignore remove bob", by "Reference 1", it tries to call "remove" on the instance associated with "ignore" in modules, and gives the argument "bob", contained in a table (with a single value).
However, on the other side of the call, the remove function does not receive the argument. I even tried to replace the "Reference 1" line with
module[command]("bob")
but I get the same result.
Here is the other function, which does not receive the argument "bob"
:
function TIF_Ignore:remove(name)
print(name) -- Reference 2
TIF_Ignore:rawremove(name)
TIF_Ignore:rawremovetmp(name)
print(title.. name.. " is not being ignored.")
end
I added "Reference 2" in my code when I was trying to figure out what was wrong. When I do "ignore remove bob", or when I replace the "unpack(args)" with "bob" on "Reference 1", the variable "name" in "remove" is still nil.
Solution
The declaration function TIF_Ignore:remove(name)
is equivalent to function TIF_Ignore.remove(self, name)
. Note the use of colon in the first case, it adds extra hidden parameter to emulate OOP and classes. The way you call the function, you pass "bob" as the self
parameter instead of name
.
To fix this you can make remove
"static function" like this: function TIF_Ignore.remove(name)
. However, you'll also have to change rawremove
and rawremovetmp
in a similar fashion, both declaration and calling site. The other (easier) option is not to remove module
from the args
table, it should be the first parameter passed.
OTHER TIPS
If you want to call a function defined with the colon :
syntax, you have to pass it an additional argument, namely the table it is expecting. Because the particular example you give does not use self
, you could switch to the dot .
syntax, but in case you need the full generality, look to the code below:
function Dynamic(msg)
local args = split(msg, " ")
local module = table.remove(args, 1)
if module and modules[module] then
module = modules[module]
local command = table.remove(args, 1)
if command then
local command = module[command]
command(module, unpack(args))
else
-- Function doesnt exist
end
else
-- Module doesnt exist
end
end
I have also fixed a number of minor problems:
- Variables should be
local
. args
is always non-nil.- Lookup
modules[module]
might fail. table.remove
returns the element removed, and it's OK to call it on an empty table.