timer.performWithDelay unexpected results

Hi all,

What values would you expect to get printed by the following simple code?  Coming from a .NET background I would expect it to print 1,2,3.

local x = 1
timer.performWithDelay( 10, function() print(x) end )
x = 2
timer.performWithDelay( 10, function() print(x) end )
x = 3
timer.performWithDelay( 10, function() print(x) end )

It actually prints 3,3,3.  Why does it not push the current value of x onto the stack rather than the end value of x?

Thanks

Adrian
 

Each “print(x)” call is telling the system to print the current value of the (file-local) variable x … since timer.performWithDelay is async, all of the x=1, x=2, x=3 statements are executed before the calls to the delay functions execute (hence they all print the same value).

Is there a reason to not use 3 separate variables (x1,x2,x3)?

To add to what jbp1 said, 10 milliseconds is an eternity in computer time.  By the time the first timer fires, x is already 3.  Those 6 instructions probably executed in millionths of a second as opposed to thousandth’s of a second.

Rob

I appreciate the async nature of the timer call, I just would of thought it would of used the current x value rather than the final x value.  My example was simplified to highlight the “issue”. 

In my case I have code in a loop firing delayed transactions on hundreds of objects modifying their x, y values where loop is the index to a collection of objects.   e.g.

for loop = 1,100 do

  x,y = getNewPosition(loop)

  timer.performWithDelay( 150, function() moveObject(x,y,loop) end )

end

Trouble is when moveObject() finally executes, x,y are always what the last values in the loop.

Seemed like a bug to me but if that is by design I will just have to code around it.

I keep thinking there’s gotta be a way to wrap the x var into a local … not sure how to do it, maybe something like this:

local x=1 repeat local y = x timer.performWithDelay( 10, function() print(y) end ) until 0 -- this should execute once x = 2 repeat ... etc. until 0

Each local y is embedded in its own separate loop so they should take on/store the value of x at that point in the code.  And that value should then be fed to the timer.perform call.

What you probably should do is something like this:

local x = 1 timer.performWithDelay(10, function() print(x); x=x+1; end, 3)

In your three iteration version from the top.

Appreciate your input guys but I’ve coded around it like this…

function doSomething()

  local x,y = {},{}

  for loop = 1,100 do

    x[loop],y[loop] = getNewPosition(loop)

    timer.performWithDelay( 150, function() moveObject(x[loop],y[loop],loop) end )

  end

end

So each function call gets it’s own value of x and y.  Weird that those values persist after they go out of scope if they are not passed in at the point of the function call?!

I guess parameters are always passed byRef rather then byVal.  I’ll just have to remember that.  Would be good if we could specify scope when passing variables to functions in Corona. 

Each “print(x)” call is telling the system to print the current value of the (file-local) variable x … since timer.performWithDelay is async, all of the x=1, x=2, x=3 statements are executed before the calls to the delay functions execute (hence they all print the same value).

Is there a reason to not use 3 separate variables (x1,x2,x3)?

To add to what jbp1 said, 10 milliseconds is an eternity in computer time.  By the time the first timer fires, x is already 3.  Those 6 instructions probably executed in millionths of a second as opposed to thousandth’s of a second.

Rob

I appreciate the async nature of the timer call, I just would of thought it would of used the current x value rather than the final x value.  My example was simplified to highlight the “issue”. 

In my case I have code in a loop firing delayed transactions on hundreds of objects modifying their x, y values where loop is the index to a collection of objects.   e.g.

for loop = 1,100 do

  x,y = getNewPosition(loop)

  timer.performWithDelay( 150, function() moveObject(x,y,loop) end )

end

Trouble is when moveObject() finally executes, x,y are always what the last values in the loop.

Seemed like a bug to me but if that is by design I will just have to code around it.

I keep thinking there’s gotta be a way to wrap the x var into a local … not sure how to do it, maybe something like this:

local x=1 repeat local y = x timer.performWithDelay( 10, function() print(y) end ) until 0 -- this should execute once x = 2 repeat ... etc. until 0

Each local y is embedded in its own separate loop so they should take on/store the value of x at that point in the code.  And that value should then be fed to the timer.perform call.

What you probably should do is something like this:

local x = 1 timer.performWithDelay(10, function() print(x); x=x+1; end, 3)

In your three iteration version from the top.

Appreciate your input guys but I’ve coded around it like this…

function doSomething()

  local x,y = {},{}

  for loop = 1,100 do

    x[loop],y[loop] = getNewPosition(loop)

    timer.performWithDelay( 150, function() moveObject(x[loop],y[loop],loop) end )

  end

end

So each function call gets it’s own value of x and y.  Weird that those values persist after they go out of scope if they are not passed in at the point of the function call?!

I guess parameters are always passed byRef rather then byVal.  I’ll just have to remember that.  Would be good if we could specify scope when passing variables to functions in Corona.