10 April 2019
Using functions for onComplete listeners
Corona API’s are some of the best thought out in the industry. We’ve worked hard to make them consistent and easy to use. Lua follows a similar thought process, attempting to be consistent with minimal syntax rules. But there are times that some concepts may not be obvious to newer developers coming to a new language and API ecosystem.
Recently a problem discussed in the forums falls into one of these “Gotcha” categories.
Calling functions vs. providing an address to a function
Let’s look at a basic Corona API, the timer.performWithDelay() API. This function requires two parameters and an optional third parameter. Let’s look at its definition:
1 |
timer.performWithDelay( delay, listener [, iterations] ) |
The first parameter, delay
is the time in milliseconds before the function passed as the listener
fires. Finally, you can set a number of times for this to run. At its basic nature, you want to wait some period of time before listener
runs.
Lets create a simple listener function for this example:
1 2 3 |
local function myListener( value ) print( "timer fired", value ) end |
It simply prints that the timer to the console log with a value. Your code could now look like:
1 2 3 |
local myValue = 10 print( "timer start" ) timer.performWithDelay( 5000, myListener( myValue ) ) |
You would expect to see in your console log that the message “timer start” show up, then 5 seconds later, you would expect to see “timer fired”. But if you run this code, you will see the two messages print simultaneously with no delay.
What happened?
In Lua, and many other languages, there are two needs:
- Call the function
- Get the functions memory address
In the case of Corona APIs that expect a function passed to it, or an onComplete
option on functions like audio.play() or transition.to(), Corona is expecting an “address to a function“. When you call a function, it executes immediately and returns a value or nil if your function doesn’t return a value.
How you do “call a function” vs “get a function’s address“
It’s pretty simple, if you put parentheses after the function name, it runs the function. If you leave off the parentheses, you get the address to the function.
So in our example above, since we included myListener( value )
, the function returns immediately and returns any return value. So we get the message from myListener()
and the resulting timer call is compiled as:
1 |
timer.performWithDelay( 5000, nil ) |
Since myListener()
doesn’t return a value, a nil is returned. Then 5 seconds later, timer.performWithDelay()
tries to run nothing. To make this work, you have to pass the address to the function. You do this by leaving off the parenthesis and not passing any parameters:
1 |
timer.performWithDelay( 5000, myListener ) |
Now after 5 seconds, myListener()
will be called, the message will print as expected.
You’re probably noticing that the value never gets passed in this way. This is how Corona works. You can’t pass values without using the (), which runs the function immediately. There is an easy way to address this using anonymous functions, but that will be a topic for another day.
Just remember if you’re providing a function to an onComplete
parameter or a function to a listener, you have to pass the address of the function.
Dream! Build! Ship!
Sorry, the comment form is closed at this time.