Using timer.simple inside a k,v in pairs loop?

Hey guys.

This is what I’m trying to test:

[lua]for k,v in pairs(player.Getall()) do
timer.Simple(1, function() v:DoSomething() end)
end[/lua]

Here’s the problem: when the timer actually runs after a second, if there was more than one value in the k,v table, then it doesn’t know which “v” to use.

Is there any way to overcome this? You can’t store v as something because it’s a pointer…

Have you tested this? It should work fine.

Rather than starting x timers you should rather put the loop IN the timer callback.

Yes, I have tested this. It gets an error saying V is null, in other words, it either got to the end of the table or v doesn’t exist anymore because the loop is over long before a second has passed.

But I know what you mean, you’d think the entity gets passed into the timer function.

That’s not how this works. The anonymous function you pass to the timer is a closure with v as an upvalue, therefore v (in the closure) will not become nil until the closure is destroyed.

[editline]5th June 2013[/editline]

In other words: it doesn’t matter if the loop has ended before the timer is run. The loop just creates closures and passes them to the timer - it doesn’t need to be alive for the upvalue to remain non-nil.

Its important not to confuse nil with null.

You get errors with null, if the entity you stored the reference to (value v) has dissapeared for whatever reason. ( In your case a player could disconnect, before the timer runs )

So, you should check if the entity is still valid, before doing anything. http://wiki.garrysmod.com/page/Global/IsValid

Why isnt All capitalised in player.Getall it should be player.GetAll()
(doubt thats actually your problem, but if thats the exact code you are testing with it would be a problem)

No, I wrote it just now. The actual code is way, way bigger.

However, putting the loops inside the timers, not the other way around, fixes this.

Is there a possibility the player left in this timescape? ( perhaps, in the actual version the timer’s much longer? )

None the less, it’s always nice to do something like this :

[lua]
for k, v in pairs( player.GetAll() ) do

timer.Simple( 5, function()

	if ( v && IsValid( v ) ) then 

		v:DoSomething();

	end

end);

end
[/lua]

[lua]
for k,v in pairs(player.GetAll()) do
local v = v
timer.Simple(5, function() v:DoSomething() end)
end
[/lua]
I think you should do it this way.

By the way, IsValid() already checks if v exists.

v already is a local variable.

No,

[lua]
timer.Simple(1, function()
for _, v in pairs(player.GetAll()) do
v:doStuff()
end
end)
[/lua]

Finally someone did it right ._.