Forward declaration help

This is a good question.  

Why does something like this work? 

local rect, reset local function draw() rect = display.newRect( display.contentCenterX, display.contentCenterY, 200, 200) rect:addEventListener( "tap", reset ) end reset = function() display.remove(rect) rect = nil draw() end draw()

Hi @mort,

I assume you mean:

[lua]

rect:addEventListener( “tap”, reset )

[/lua]

and not :

[lua]

rect1:addEventListener( “tap”, reset )

[/lua]

I don’t see any other citation of “rect1” in your code.


Anyway (for @jvmaster77 too), the reason @mort’s code works is because, when you just create an empty reference, it doesn’t contain any “methods” in regards to Corona. So, you can’t add an event listener to it (because it’s essentially nothing at that point). However, when you assign a display object to this variable, internally you also provide it with a series of object-appropriate methods and properties that Corona can use, i.e. the ability to assign an event listener, among other things.

Does that explain it better?

Brent

@Brent: Thanks, that was a typo.

However, I think we’re both more concerned with why adding an event listener with a forward-declared listener function doesn’t work. (I apologize for not making it clearer before, by saying I was talking about the referenced function, and not referenced display object.)

Like so:

local reset local rect = display.newRect( display.contentCenterX, display.contentCenterY, 200, 200) rect:addEventListener( "tap", reset ) reset = function() display.remove(rect) rect = nil end

vs. my previous example, whereby it somehow works when an addEventListener is called within an enclosing function (i.e. draw).

There is a huge difference between this form…

local someFunction local function otherFunction(x) return someFunction(x + 1) end someFunction = function(x) return x+1 end print(otherFunction(0)) -- this'll work, prints 2

…which uses only “native Lua” calling “native Lua” and will defer the evaluation of “someFunction” within “otherFunction” until actually called, so everything works as expected…

…and THIS form (as per jvmaster77)…

local someListener someDisplayObject:addEventListener("whatever", someListener) someListener = function(event) -- will never be called end

…which attempts to pass a reference to a not-yet-existent function to an internal API routine, so the API gets a nil when expecting a function, so no event is ever gonna fire that function, as the API has no way to know what function you intended to provide itwith (or even if you ever got around to actually defining it AT ALL!)

That is, addEventListener() isn’t passed the “name” of the function to lookup later, it’s passed a reference – but it’s a nil reference to something that doesn’t exist yet, there is no memory address allocated for a function by simply writing “local someListener”. By the time you actually DO define the function and allocate storage for it in the next line, it’s too late, the API will never know about it.

It’s a bit like trying to create a closure around a forward declaration - the two concepts are mutually at odds with each other: you either need the reference as it exists NOW… or not, and instead wish to access whatever that variable references at some time in the future. Sending references to the API is like the closure scenario – it’s gonna pass the value as it exists *right now*.

fwiw, hth

@davebollinger, @Brent: Great explanations, thanks! Together they are two very nice perspectives/unique ways of explaining the issue.

However, why does something like this work (when adding a referenced listener function)?

In other words, why does wrapping “rect:addEventListener…” in a function make any difference?

EDIT: I think I see the difference.

Regardless of the initial ordering of the functions, and even if the lower (reset) function is referenced above the upper one (add), I still have to CALL the upper function (add) after the lower one (when involving an API call, that is)?

local reset local rect = display.newRect( display.contentCenterX, display.contentCenterY, 200, 200) local function add() rect:addEventListener( "tap", reset ) end reset = function() display.remove(rect) rect = nil print("tapped") end add()

It all boils down to “when does it actually happen?” (retrieving the value of the variable, that is)

In your example, nothing actually happens until you call add() at the very end. Inside the execution of add(), Lua will scan up through environment scope to find/retrieve the value of a variable named “reset” (the “closest” of which currently happens to contain a function - yeah!) and push that value (a reference to the function) as a parameter to the addEventListener() call, so all is well.

hth

@dave

Thanks! 

So, by calling add() after the actual reset function, I’m essentially letting the variable reference know that the reset function exists (since add() has the actual reset function in scope!)

“add()” sees “reset = function()”; allows “local reset” (the reference) to know location of “reset = function()”; the listener can now call “reset = function()” through the reference.