Simple way to call function after another function is complete? (without using coroutines)

Hi All,

Sorry if I am missing something obvious, but I was wondering if there is a simple way to call a function after the execution of another function is complete that doesn’t involve using coroutines?

Basically I would like to do something like the following:

performAfterComplete( myFunction1, {onComplete = myFunction2} )

–myFunction2 is called only after the entirety of the code of myFunction1 has completed execution

Is there a simple way to do something like this?

Much thanks in advance!

KC

Lua isn’t multithreaded, so the behaviour you want happens by default, just call your functions sequentially - upon calling myFunction1() it will fully execute then return, then call myFunction2() which will also fully execute then return before the next line of code that follows:

myFunction1() myFunction2() -- whatever happens next will occur sequentially after both above

If you need a “one-liner”, perhaps as something you can pass to a timer event for example, then just “wrap” them, like so:

local function myTwoFunctions() myFunction1() myFunction2() end timer.performWithDelay(1000,myTwoFunctions)

or wrap them on-the-fly anonymously like so

timer.performWithDelay(1000, function() myFunction1() myFunction2() end)

hth

Hi davebollinger,

Thank you for your reply. You bring up a very good point about Lua being single-threaded.

Lua usually executes code in the order which they are called (as you mentioned), but there are exceptions. My apologies for failing to mention my code contains these “exceptions”.

Consider the following code:

local function a() for i = 1, 3 do print("a") end end local function b() for i = 1, 3 do print("b") end end a() b() 

Thanks to Lua being single-threaded, the output (always) is:

a a a b b b

However, see what happens when you modify the code slightly so that it becomes:

local function a() for i = 1, 3 do timer.performWithDelay(10, function () print("a") end) end end local function b() for i = 1, 3 do print("b") end end a() b()

Now the output becomes:

b b b a a a

Obviously, in my actual code I am doing much more than merely printing output, and the order in which the functions are called is crucial (i.e. I have a order-sensitive routine).

Which is why I need something like performAfterComplete( myFunction1, {onComplete = myFunction2} ), and hence my original post.

Do you know of a simple why to achieve this?

Thanks!

KC

Hi KDC.

Out of curiosity, are there any major “no coroutines” reasons?

You might take a look at some of the promises libraries out there, say this or this (this second one has links to several more, down at the bottom). I imagine each one has different requirements on your end, but maybe some are pretty good fits. For instance, looks like Billiam’s would have you implement dolater(), which seems to map fairly directly to timers.

If you ever do need multithreading, I’ve got a plugin for that.

Hi StarCrunch,

Thank you for your reply.

The short answer is “no”.

The slightly longer answer is that coroutines tend to be messy, complicated, makes code much harder to read, and has certain limitations when implemented in the context of Corona.

However, if it means that I have to implement third-party libraries to avoid coroutines, I’d just rather use them :stuck_out_tongue:

KC

so, … all three independent timers “a” need to complete before any of the three independent timers “b” begin?  is that a correct restatement of the problem?

if so, you’ll need some sort of “promise” system, though you could roll your own with just a set of semaphores:  have each timer “a” set a semaphore when completed, have those semaphores “watched” during change so that when all three become set it does something (fires off three “b” timers) and disables itself.

the real problem is that you have 3x1 timers (three independent timers that do one thing each), and the problem would be greatly simplified if you could refactor it into 1x3 timers (one single timer that does three things).  then when that one timer completes you could use Corona’s built-in “onComplete” mechanism for the “a”'s to fire off another 1x3 timer for the “b”'s [EDIT:  i’m scrambling timers/transitions here, oops, but refactoring point remains:  have 1 timer that prints 3 a’s, then set a timer to print 3 b’s)

three independent timers have another problem, if you assume that they themselves will be synchronous, because they’re not - even your “a”'s aren’t guaranteed to be synchronous, they’re truly independent.  it’s too much to get into here, as to real-time versus the non-zero time it takes to execute your loop, but run; the following code for an hours and see if it prints any “OOPS”, then do some self-study to figure out why.  misunderstanding this can lead to some really hard to debug problems.

local frameCounter = 0 local semaphore = { 0,0,0 } local DELAY = 100 local function flag1() semaphore[1]=frameCounter end local function flag2() semaphore[2]=frameCounter end local function flag3() semaphore[3]=frameCounter end local function startem() -- these three timers are independent, and NOT guaranteed to complete during the same frame timer.performWithDelay(DELAY,flag1); semaphore[1]=0 timer.performWithDelay(DELAY,flag2); semaphore[2]=0 timer.performWithDelay(DELAY,flag3); semaphore[3]=0 end local function checkem() -- have all timers fired yet? if (semaphore[1]\>0 and semaphore[2]\>0 and semaphore[3]\>0) then -- did they all fire on the same frame?? if (semaphore[1]==semaphore[2] and semaphore[2]==semaphore[3]) then -- fine, no problem --print("OK") else -- oops, told ya so print("OOPS", semaphore[1], semaphore[2], semaphore[3]) end -- do it all again startem() end end local function onEnterFrame() checkem() frameCounter = frameCounter + 1 end Runtime:addEventListener("enterFrame", onEnterFrame) startem()

Lua isn’t multithreaded, so the behaviour you want happens by default, just call your functions sequentially - upon calling myFunction1() it will fully execute then return, then call myFunction2() which will also fully execute then return before the next line of code that follows:

myFunction1() myFunction2() -- whatever happens next will occur sequentially after both above

If you need a “one-liner”, perhaps as something you can pass to a timer event for example, then just “wrap” them, like so:

local function myTwoFunctions() myFunction1() myFunction2() end timer.performWithDelay(1000,myTwoFunctions)

or wrap them on-the-fly anonymously like so

timer.performWithDelay(1000, function() myFunction1() myFunction2() end)

hth

Hi davebollinger,

Thank you for your reply. You bring up a very good point about Lua being single-threaded.

Lua usually executes code in the order which they are called (as you mentioned), but there are exceptions. My apologies for failing to mention my code contains these “exceptions”.

Consider the following code:

local function a() for i = 1, 3 do print("a") end end local function b() for i = 1, 3 do print("b") end end a() b() 

Thanks to Lua being single-threaded, the output (always) is:

a a a b b b

However, see what happens when you modify the code slightly so that it becomes:

local function a() for i = 1, 3 do timer.performWithDelay(10, function () print("a") end) end end local function b() for i = 1, 3 do print("b") end end a() b()

Now the output becomes:

b b b a a a

Obviously, in my actual code I am doing much more than merely printing output, and the order in which the functions are called is crucial (i.e. I have a order-sensitive routine).

Which is why I need something like performAfterComplete( myFunction1, {onComplete = myFunction2} ), and hence my original post.

Do you know of a simple why to achieve this?

Thanks!

KC

Hi KDC.

Out of curiosity, are there any major “no coroutines” reasons?

You might take a look at some of the promises libraries out there, say this or this (this second one has links to several more, down at the bottom). I imagine each one has different requirements on your end, but maybe some are pretty good fits. For instance, looks like Billiam’s would have you implement dolater(), which seems to map fairly directly to timers.

If you ever do need multithreading, I’ve got a plugin for that.

Hi StarCrunch,

Thank you for your reply.

The short answer is “no”.

The slightly longer answer is that coroutines tend to be messy, complicated, makes code much harder to read, and has certain limitations when implemented in the context of Corona.

However, if it means that I have to implement third-party libraries to avoid coroutines, I’d just rather use them :stuck_out_tongue:

KC

so, … all three independent timers “a” need to complete before any of the three independent timers “b” begin?  is that a correct restatement of the problem?

if so, you’ll need some sort of “promise” system, though you could roll your own with just a set of semaphores:  have each timer “a” set a semaphore when completed, have those semaphores “watched” during change so that when all three become set it does something (fires off three “b” timers) and disables itself.

the real problem is that you have 3x1 timers (three independent timers that do one thing each), and the problem would be greatly simplified if you could refactor it into 1x3 timers (one single timer that does three things).  then when that one timer completes you could use Corona’s built-in “onComplete” mechanism for the “a”'s to fire off another 1x3 timer for the “b”'s [EDIT:  i’m scrambling timers/transitions here, oops, but refactoring point remains:  have 1 timer that prints 3 a’s, then set a timer to print 3 b’s)

three independent timers have another problem, if you assume that they themselves will be synchronous, because they’re not - even your “a”'s aren’t guaranteed to be synchronous, they’re truly independent.  it’s too much to get into here, as to real-time versus the non-zero time it takes to execute your loop, but run; the following code for an hours and see if it prints any “OOPS”, then do some self-study to figure out why.  misunderstanding this can lead to some really hard to debug problems.

local frameCounter = 0 local semaphore = { 0,0,0 } local DELAY = 100 local function flag1() semaphore[1]=frameCounter end local function flag2() semaphore[2]=frameCounter end local function flag3() semaphore[3]=frameCounter end local function startem() -- these three timers are independent, and NOT guaranteed to complete during the same frame timer.performWithDelay(DELAY,flag1); semaphore[1]=0 timer.performWithDelay(DELAY,flag2); semaphore[2]=0 timer.performWithDelay(DELAY,flag3); semaphore[3]=0 end local function checkem() -- have all timers fired yet? if (semaphore[1]\>0 and semaphore[2]\>0 and semaphore[3]\>0) then -- did they all fire on the same frame?? if (semaphore[1]==semaphore[2] and semaphore[2]==semaphore[3]) then -- fine, no problem --print("OK") else -- oops, told ya so print("OOPS", semaphore[1], semaphore[2], semaphore[3]) end -- do it all again startem() end end local function onEnterFrame() checkem() frameCounter = frameCounter + 1 end Runtime:addEventListener("enterFrame", onEnterFrame) startem()