How to dynamically call a function in Corona?

Hi all,

May I know how to dynamically call a function in Corona?

I would like to call a function like this…

display[i] ( )

Is it possible to do that?

Best Regards,

John

I’m not sure if this is what you are after, but I found a similar question (“lua call function from a string with function name”) answered here:

http://stackoverflow.com/questions/1791234/lua-call-function-from-a-string-with-function-name

@apple_id7,

Hi.  Unfortunately, you cannot use the Lua loadstring() and loadfile() functions because they are disabled.  Why?  Because Apple does not allow dynamic code execution. i.e. No real-time scripting.

That said, there is always a way.  I’ll give you a partial solution and let you take it from there…

local functions = {} -- First arg is 'reference' to function or the name of that function, the second argument tells the parser whether to expect a value in return -- -- Note: I don't actually use the 'hasReturn' flag, but I did it this way to show you a way of adding 'details' about individual functions you can use later. -- functions["print"]         = { cmdRef = "print",          hasReturn = false } functions["create circle"] = { cmdRef = display.newCircle, hasReturn = true } functions["set fill last"] = { cmdRef = "setFillColor" ,   hasReturn = false } local function commandParser( commands )     local lastRet = {}     local last      local retVal      local cmd     local args     local cmdRef     local hasReturn = false     for i = 1, #commands do         cmd       = commands[i].cmd         args      = commands[i].args         cmdRef    = functions[cmd].cmdRef         hasReturn = functions[cmd].hasReturn         last = lastRet[#lastRet] -- May be nil         print( "-------------------------------------------" )         print( i, cmd, unpack(args), cmdRef, hasReturn )             retVal = nil                  -- Print Handler         --         if(    cmd == "print" ) then             cmdRef = \_G[cmdRef] -- Get the print function out of the globals table             retVal = cmdRef( unpack( args ) )         elseif(    cmd == "create circle" ) then             retVal = cmdRef( unpack( args ) )         elseif(    cmd == "set fill last" ) then             cmdRef = last[cmdRef] -- Get a reference to 'setFillColor' off of the last object we created             retVal = cmdRef( last, unpack( args ) ) -- Call setFillColor like a function and pass last object as first argument                  end         -- Store return value if found         if(retVal) then            lastRet[#lastRet] = retVal           end             end end -- =================================================================== -- === NOW LET'S USE THE ABOVE 'PARSER' -- =================================================================== local tableOfCommands = {} -- cmd - command to execute -- args - arguments to pass to command -- tableOfCommands[1] = { cmd = "print", args = { "hello", "this is a", "test", 0xed15c001 } } tableOfCommands[2] = { cmd = "create circle", args = { 100, 100, 20 } } tableOfCommands[3] = { cmd = "set fill last", args = { 255, 0, 0 } } tableOfCommands[4] = { cmd = "create circle", args = { 200, 150, 25 } } tableOfCommands[5] = { cmd = "set fill last", args = { 255, 0, 255 } } commandParser( tableOfCommands )  

The above code ‘dynamically’ parses a table of ‘commands’ and executes them, giving this result:

dynamicCoding.png

The table of commands was created statically in this case, but there is no reason why it could not be assembled on the fly.

Again, I’ll leave this to your imagination,…

PS - I love the fact that the forums support code formatting, but the wonky thing always adds extra carriage returns… OK.  Fixed, now the code should look more legible.

PPS - If this solution works for you, please mark this thread as solved.

Going back to the original post, though, if the goal is to make a function call like

[lua]

displayi

[/lua]

such that the function that gets called varies depending on what ‘i’ is, then you should just make ‘display’ a table and the items in the table the functions you want to call.  You can make the keys to the table anything you like – integers (like an array) and strings are of course the most common.

Actually, we shouldn’t name the table ‘display’, since that’s the name of a Corona library – a pretty important one too  :-) – but give it some other name and it would be fine.

  • Andrew

Note: If you want to grab the sample instead of cutting and pasing, you can get it here: 

https://github.com/roaminggamer/RG_FreeStuff/tree/master/Dynamic%20Code

Hi roaminggamer,

Actually,I would like to create a function array.Is it possible to do that in Corona? 

Best Regards,

John

Sure its possible to make an table (array) of references to global functions, but then that is actually what _G is

print("Cool") -- same as \_G["print"]("Cool") 

Making a table of methods (functions attached to display objects, etc.) is a little trickier, but also doable.

local methodTable = {} local obj1 = display.newCircle( 10, 10, 10 ) local obj2 = display.newCircle( 30, 30, 10 ) -- Store reference to obj1's setFillColor method. methodTable["setFillColor"] = obj1.setFillColor -- Grabbing reference from table in local variable to make code more legible, -- local func = methodTable["setFillColor"] -- If I recall, this will work: -- -- Use reference to obj1's setFillColor method to set color of obj2 func( obj2, 255, 0, 0 ) -- Above equivalent to this: methodTable["setFillColor"]( obj2, 255, 0, 0 )  -- I've never tried it, but this might work too, assuming display objects all -- share the same implementation for setFillColor() -- local obj3 = display.newRect(50,50,20,20) -- Use reference to obj1's (a circle) setFillColor method to set color of obj3 ( a rect) func( obj3, 255, 0, 0 )  

just a reminder making a table named display will likely disable access to the included display.* calls, like creating images.

I’m not sure if this is what you are after, but I found a similar question (“lua call function from a string with function name”) answered here:

http://stackoverflow.com/questions/1791234/lua-call-function-from-a-string-with-function-name

@apple_id7,

Hi.  Unfortunately, you cannot use the Lua loadstring() and loadfile() functions because they are disabled.  Why?  Because Apple does not allow dynamic code execution. i.e. No real-time scripting.

That said, there is always a way.  I’ll give you a partial solution and let you take it from there…

local functions = {} -- First arg is 'reference' to function or the name of that function, the second argument tells the parser whether to expect a value in return -- -- Note: I don't actually use the 'hasReturn' flag, but I did it this way to show you a way of adding 'details' about individual functions you can use later. -- functions["print"]         = { cmdRef = "print",          hasReturn = false } functions["create circle"] = { cmdRef = display.newCircle, hasReturn = true } functions["set fill last"] = { cmdRef = "setFillColor" ,   hasReturn = false } local function commandParser( commands )     local lastRet = {}     local last      local retVal      local cmd     local args     local cmdRef     local hasReturn = false     for i = 1, #commands do         cmd       = commands[i].cmd         args      = commands[i].args         cmdRef    = functions[cmd].cmdRef         hasReturn = functions[cmd].hasReturn         last = lastRet[#lastRet] -- May be nil         print( "-------------------------------------------" )         print( i, cmd, unpack(args), cmdRef, hasReturn )             retVal = nil                  -- Print Handler         --         if(    cmd == "print" ) then             cmdRef = \_G[cmdRef] -- Get the print function out of the globals table             retVal = cmdRef( unpack( args ) )         elseif(    cmd == "create circle" ) then             retVal = cmdRef( unpack( args ) )         elseif(    cmd == "set fill last" ) then             cmdRef = last[cmdRef] -- Get a reference to 'setFillColor' off of the last object we created             retVal = cmdRef( last, unpack( args ) ) -- Call setFillColor like a function and pass last object as first argument                  end         -- Store return value if found         if(retVal) then            lastRet[#lastRet] = retVal           end             end end -- =================================================================== -- === NOW LET'S USE THE ABOVE 'PARSER' -- =================================================================== local tableOfCommands = {} -- cmd - command to execute -- args - arguments to pass to command -- tableOfCommands[1] = { cmd = "print", args = { "hello", "this is a", "test", 0xed15c001 } } tableOfCommands[2] = { cmd = "create circle", args = { 100, 100, 20 } } tableOfCommands[3] = { cmd = "set fill last", args = { 255, 0, 0 } } tableOfCommands[4] = { cmd = "create circle", args = { 200, 150, 25 } } tableOfCommands[5] = { cmd = "set fill last", args = { 255, 0, 255 } } commandParser( tableOfCommands )  

The above code ‘dynamically’ parses a table of ‘commands’ and executes them, giving this result:

dynamicCoding.png

The table of commands was created statically in this case, but there is no reason why it could not be assembled on the fly.

Again, I’ll leave this to your imagination,…

PS - I love the fact that the forums support code formatting, but the wonky thing always adds extra carriage returns… OK.  Fixed, now the code should look more legible.

PPS - If this solution works for you, please mark this thread as solved.

Going back to the original post, though, if the goal is to make a function call like

[lua]

displayi

[/lua]

such that the function that gets called varies depending on what ‘i’ is, then you should just make ‘display’ a table and the items in the table the functions you want to call.  You can make the keys to the table anything you like – integers (like an array) and strings are of course the most common.

Actually, we shouldn’t name the table ‘display’, since that’s the name of a Corona library – a pretty important one too  :-) – but give it some other name and it would be fine.

  • Andrew

Note: If you want to grab the sample instead of cutting and pasing, you can get it here: 

https://github.com/roaminggamer/RG_FreeStuff/tree/master/Dynamic%20Code

Hi roaminggamer,

Actually,I would like to create a function array.Is it possible to do that in Corona? 

Best Regards,

John

Sure its possible to make an table (array) of references to global functions, but then that is actually what _G is

print("Cool") -- same as \_G["print"]("Cool") 

Making a table of methods (functions attached to display objects, etc.) is a little trickier, but also doable.

local methodTable = {} local obj1 = display.newCircle( 10, 10, 10 ) local obj2 = display.newCircle( 30, 30, 10 ) -- Store reference to obj1's setFillColor method. methodTable["setFillColor"] = obj1.setFillColor -- Grabbing reference from table in local variable to make code more legible, -- local func = methodTable["setFillColor"] -- If I recall, this will work: -- -- Use reference to obj1's setFillColor method to set color of obj2 func( obj2, 255, 0, 0 ) -- Above equivalent to this: methodTable["setFillColor"]( obj2, 255, 0, 0 )  -- I've never tried it, but this might work too, assuming display objects all -- share the same implementation for setFillColor() -- local obj3 = display.newRect(50,50,20,20) -- Use reference to obj1's (a circle) setFillColor method to set color of obj3 ( a rect) func( obj3, 255, 0, 0 )  

just a reminder making a table named display will likely disable access to the included display.* calls, like creating images.