I am using functions from a lua-based library and I would like to store those different functions with varying parameter counts in a queue to be executed later on when I need to. Here is a similar question and solution for javascript.
Below is an example that works, but conditionals are done manually for each parameter count. Is there a cleaner way to do this in lua? Keep in mind I cannot modify the library's function implementation since I dont have access to their code.
Action = {}
function Action:new(func, ...)
newObj = {
func = func or nil,
args = {...} or {}
}
self.__index = self
return setmetatable(newObj, self)
end
function Action:execute()
if #self.args == 0 then
self.func()
elseif #self.args == 1 then
self.func(self.args[1])
elseif #self.args == 2 then
self.func(self.args[1], self.args[2])
-- and so on
end
theQueue = {
Action:new(aFunc, param),
Action:new(aDifferentFunc, param1, param2)
}
for _, action in ipairs(theQueue) do
action:execute()
end
You can simply use table.unpack to convert your args table back to a parameter list.
self.func(table.unpack(self.args))
newObj should be local btw.
This looks like a perfect case for anonymous functions:
local theQueue = {
function() aFunc(param) end,
function() aDifferentFunc(param1, param2) end,
}
for _, action in ipairs(theQueue) do
action()
end
Related
NativeTable = {
["print"] = {},
["LoadResourceFile"] = {}
}
for k, v in pairs(NativeTable) do
k = function(...)
print("test")
end
end
this would result in defining them in the NativeTable and not as a global function
print = function(...)
print("test")
end
LoadResourceFile = function(...)
print("test")
end
So I'm trying to define a global function with a table name
Guess i could do smth like this
But there must be a better way?
NativeTable = {
["test"] = {},
["LoadResourceFile"] = {}
}
local function OverWriteFunction(FuncName, Func)
local Base = [[ = function(...)
print("jaa")
end
]]
local Final = FuncName .. Base
return Final
end
for k, v in pairs(NativeTable) do
load(OverWriteFunction(k))()
end
In your first example you are redefining the variable k, that is local inside the for loop, so this will not be usable outside the one loop where you define it.
Your second example is something you absolutely should avoid if you can, since defining code inside a string and loading it later means, that even only a syntax error will not be shown on "compiling" it, but only when that exact part is executed. And especially, when you are concatenating string that are meant to be code, you just get the risk of glueing something together wrongly, if you try to have that made generically.
If I understood correctly what you are trying to achieve, I would say, it could be something like this:
NativeTable = {
["test"] = {},
["LoadResourceFile"] = {},
[3] = {}
}
for k, v in pairs(NativeTable) do
if type(k) == "string" then
_G[k] = function(...)
print("output")
end
end
end
test()
LoadResourceFile()
-- _G[3]()
Which outputs:
output
output
What I have done here is to use the _G table which is the global environment of lua, all things you define there with a string in the brackets will be globally available (and what is globally available is inside that table, so be careful, since you can override other functions and variables you have defined!), even when writing it as a normal function call. I did also make sure, to only do this, when the type of k was string, otherwise you could start to define functions that can be called like the last commented out call.
This doesn't make too much sense for me:
NativeTable = {
["print"] = {},
["LoadResourceFile"] = {}
}
for k, v in pairs(NativeTable) do
k = function(...)
print("test")
end
end
First you create a table with table elements print and LoadResourceFile.
Then you iterate over that table and replace the table elements with functions.
Why not simply do this:
myTable = {
a = function() print("I'm function a") end,
b = function() print("I'm function b") end,
}
or
myTable = {}
myTable.a = function () print("I'm function a") end
Then you can call the global function like so: myTable.a()
If you insist on having those functions outside of a table you can simply insert them into the global environment table.
for k, v in pairs(myTable) do _G[k] = v end
then you could call a and b globally. But whatever you're trying to accomplish there's probably a better way than this.
For some reason it doesn't appear to work to pass in a table key as a function argument, what is the trick to do this?
I'm trying to wrap the for loop iteration technique in vanilla Lua into a function that has three arguments: (1) the table to iterate, (2) the table_key to check each time, and (3) the value to find. If a match is found, return it, otherwise return nil.
function table_find_match(table, table_key, match_value)
for i=1, #table do
local this = table[i]
if this[table_key] == match_value then
return this[table_key]
end
end
return nil
end
local table_example = {
{
key_example = "string_value_1"
},
{
key_example = "string_value_2"
}
}
local result = table_find_match(table_example, key_example, "string_value_1")
print(result)
Found a solution, if I pass in the table key as a string it works, such as
table_find_match(table_example, "key_example", "string_value_1")
but I really dislike having to convert it into a string, if anyone knows any other workaround to this please share
If you pass it like table_find_match(table_example, key_example, "string_value_1")
the key_example is now considered as a (nil) variable if not defined before executing, so it has to be like
local key_example = "key_example"
local result = table_find_match(table_example, key_example, "string_value_1")
print(result)
Can you alias a function (not in a class) in LUA in a similar way to Ruby? In ruby you would do something like this:
alias new_name_for_method method()
def method()
new_name_for_method() # Call original method then do custom code
i = 12 # New code
end
I'm asking because I'm developing for a program that uses LUA scripting and I need to override a function that is declared in a default file.
In Lua, functions are values, treated like any other value (number, string, table, etc.) You can refer to a function value via as many variables as you like.
In your case:
local oldmethod = method
function method(...)
oldmethod(...)
i = 12 -- new code
end
keep in mind that
function method() end
is shorthand for:
method = function() end
function() end just creates a function value, which we assign to the variable method. We could turn around and store that same value in a dozen other variables, or assign a string or number to the method variable. In Lua, variables do not have type, only values do.
More illustration:
print("Hello, World")
donut = print
donut("Hello, World")
t = { foo = { bar = donut } }
t.foo.bar("Hello, World")
assert(t.foo.bar == print) -- same value
FYI, when wrapping a function, if you want its old behavior to be unaffected for now and forever, even if its signature changes, you need to be forward all arguments and return values.
For a pre-hook (new code invoked before the old), this is trivial:
local oldmethod = method
function method(...)
i = 12 -- new code
return oldmethod(...)
end
A post-hook (new code invoked after the old) is a bit more expensive; Lua supports multiple return values and we have to store them all, which requires creating a table:
local oldmethod = method
function method(...)
local return_values = { oldmethod(...) }
i = 12 -- new code
return unpack(return_values)
end
In lua, you can simply override a variable by creating a new function or variable with the same name.
function name_to_override()
print('hi')
end
If you still want to be able to call the old function:
local old_function = name_to_override
function name_to_override()
old_function()
print('hi')
end
I need to create a structure. The structure must contain an array of "boolean conditions". Something like this:
function ReturnStructure ()
local structure = {
{A < 10},
{B == "smth"},
{FunctionReturnsTrueOrFalse(params)},
--...
}
return structure
end
structure = ReturnStructure()
print(structure[1][1]) -- prints true or false depending on the value of A
In fact these tables contain true or false, not conditions, because when we call function ReturnStructure and it creates a local table structure, all conditions in the fields will be executed. I want to create a structure whose fields will contain not boolean values, but something that I can execute (when I want to do it) and get a boolean value. I can achieve this by using anonymous functions:
function ReturnStructure ()
local structure = {
{function() return A < 10 end},
{function() return B == "smth" end},
{FunctionReturnsTrueOrFalse, params}, -- I don't call function in this line, a just put its adress and parameters to table.
--...
}
return structure
end
structure = ReturnStructure()
print(structure[1][1]) -- prints function: 0x109bdd0
print(structure[1][1]()) -- prints true or false. I execute condition in this string.
So, there is a code which works as I want it to, but it seems very ugly.
I want to hear some ideas on how to create a simpler and more beautiful table, without printing function () return ... in every field. I think that I should use a simple OOP implementation to create my structure as an object, but I don't know how to do it. I also will be happy to get some references to methods, implementations, articles etc., which can help me to find some ideas.
I want to hear some ideas on how to create a simpler and more beautiful table, without printing function () return ... in every field.
There aren't. If Lua had C#'s lambda syntax, you could write:
local structure = {
() => A < 10,
() => B == "smth",
() => FunctionReturnsTrueOrFalse(params),
But Lua likes to keep things small and simple, to avoid adding size and complexity to the language and its implementation, so we have one syntax for one function type.
You could store them as strings, then compile and run them later, but that's choosing form over function. You don't want to be invoking the compiler unnecessarily.
local structure = {
'A < 10',
'B == "smth"',
'FunctionReturnsTrueOrFalse(params)',
So your original solution is better. I don't particularly like the way that the first two items defer evaluating their arguments, while your third example evaluates the parameters at compile time. It would be more consistent to treat the FunctionReturnsTrueOrFalse the same
local structure = {
function() return A < 10 end,
function() return B == "smth" end,
function() return FunctionReturnsTrueOrFalse(param1) end,
This also means you don't need to put them in tables. Each is just a function you call, which simplifies the calling code as well.
If you really wanted to evaluate FunctionReturnsTrueOrFalse's arguments at compile time, I'd write a utility routine to build a closure from a function and its arguments:
local function bind(f, ...)
local args = {...}
return function() f(unpack(args)) end
end
Then use that to bind the function to its args:
local structure = {
function() return A < 10 end,
function() return B == "smth" end,
bind(FunctionReturnsTrueOrFalse, param1, param2, param3),
Then everything in your table is simply a function so you don't need special handling
function ReturnStructure ()
local structure = {
{'A < 10'},
{'B == "smth"'},
{FunctionReturnsTrueOrFalse, 'parameter'},
}
local function call_me(f, ...)
return (type(f)=='function' and f or
assert((load or loadstring)('return '..f)))(...)
end
return setmetatable({}, {
__index =
function(t,k)
if structure[k] then
return call_me((table.unpack or unpack)(structure[k]))
end
end,
__newindex = function(t,k,v) structure[k] = v end
})
end
A = 2
B = "anything"
function FunctionReturnsTrueOrFalse(par)
return #par > 5
end
structure = ReturnStructure()
print(structure[1]) -- true
print(structure[2]) -- false
print(structure[3]) -- true
structure[4] = {'1==0'}
print(structure[4]) -- false
I have the following problem, somebody can help me?
comp = {}
comp.__index = function(obj,val)
if val == "insert" then
return rawget(obj,"gr")["insert"]
end
return rawget(obj, val)
end
comp.new = function()
local ret = {}
setmetatable(ret, comp)
ret.gr = display.newGroup()
return ret
end
local pru = comp.new()
pru.gr:insert(display.newImage("wakatuBlue.png"))
This line works, but I don't want to access the insert method using the gr property, I want to call the insert method directly and the metatable __index function does the work
pru:insert(display.newImage("wakatuBlue.png"))
This line doesn't work and I get this error: "bad argument #-2 to 'insert' (Proxy expected, got nil)", but this is the way that I'm looking to use
Do you want something like this?
comp = {}
comp.__index = function(obj,val)
if val == "insert" then
return rawget(obj,"gr"):insert(val)
end
return rawget(obj, val)
end
__index works just fine; it's because your last call is interpreted as:
pru.insert(pru, display.newImage("wakatuBlue.png"))
whereas you want/need it to be:
pru.insert(pru.gr, display.newImage("wakatuBlue.png"))
You either need to call it like this or explain what you are trying to do.