Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

invalid key to 'next' in function '(for generator)'
Started by Caleb P Aug 12 2013 06:09 AM

- - - - -
13 replies to this topic
next invalid for generator
[TOPIC CONTROLS]
This topic has been archived. This means that you cannot reply to this topic.
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

Caleb P

[GLOBAL: userInfoPane.html]
Caleb P
  • Corona Geek

  • 1,424 posts
  • Corona SDK

What would cause this error?

 

 
2013-08-12 07:47:25.102 Corona Simulator[1909:1c03] Runtime error
invalid key to 'next'
stack traceback:
    [C]: ?
    [C]: in function '(for generator)'
    ...
 
I'm iterating through a perfectly valid table, using pairs(). Every now and then, apparently for no reason, it'll throw that error.


[TOPIC: post.html]
#2

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 26,534 posts
  • Enterprise

Is there some event triggering that might be deleting entries from your table as your looping through it?



[TOPIC: post.html]
#3

Caleb P

[GLOBAL: userInfoPane.html]
Caleb P
  • Corona Geek

  • 1,424 posts
  • Corona SDK

Am I not supposed to remove things from a table when iterating through it? I am removing things from it - could that be the problem?

 

- C



[TOPIC: post.html]
#4

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 26,534 posts
  • Enterprise

You can remove them while iterating through. What I was asking is do you have something else like a collision detection event, a runtime listener or something that could be removing items for you while you are trying to remove them.

[TOPIC: post.html]
#5

Caleb P

[GLOBAL: userInfoPane.html]
Caleb P
  • Corona Geek

  • 1,424 posts
  • Corona SDK

I'm using my own timer solution library, so it's iterating through my list of timers. I'm also stopping a timer sometimes when it's iterated. I checked into my program, and here's the result:

 

- Eternal timer running to fire shots from a turret
  - Within the fire function, it first checks a flag to see whether it should stop on this shot
    - If flag is true, stops the timer and resets the flag
      -> Error is thrown
    - Otherwise proceeds
  - Otherwise it fires
- End of fire function

 

So if removing the index (stopping the timer) within the iteration isn't something you're supposed to do, how would I achieve this?

 

- C



[TOPIC: post.html]
#6

SegaBoy

[GLOBAL: userInfoPane.html]
SegaBoy
  • Contributor

  • 635 posts
  • Corona SDK

Be good to see some code - the only thing I can guess at this stage is whether you're facing the "iterate-backwards" approach required when deleting entries from a table.

 

http://stackoverflow.com/questions/12394841/safely-remove-items-from-an-array-table-while-iterating



[TOPIC: post.html]
#7

Caleb P

[GLOBAL: userInfoPane.html]
Caleb P
  • Corona Geek

  • 1,424 posts
  • Corona SDK

I'm using pairs()...

 

Here's some code:

 

Relavent timer code:

------------------------------
-- The iteration function
------------------------------
 
    for k, v in pairs(timerStack) do
        if timerStack[k] and timerStack[k].running then -- Not paused
            --print("iterating "..k)
            if time>=(timerStack[k].time * timerStack[k].iterCount)+timerStack[k].timeOffset then
                timerStack[k].iterCount=timerStack[k].iterCount+1 -- Number of iterations
                if timerStack[k].iterations>1 then
                    timerStack[k].iterations=timerStack[k].iterations-1
                    timerStack[k].func()
                elseif timerStack[k].iterations==1 then -- Finished iterations
                    timerStack[k].func()
                    timerStack[k].onComplete()
                    timerStack[k] = nil
                end
 
 
------------------------------
-- The stop function
------------------------------
-- After various nil checks...
 
timerStack[handle._timerStack_key] = nil -- Delete a timer
handle = nil

 

And here's the relavent turret code:

 
if turret.stopAfterNextFire then -- Stop for updates so we can reset the turret's fire speed
                spark.stop(turret.fireTimer)
                turret.fireTimer = spark.timer(turret.speed, turret.fire, 0)  -- turret.fire is the function that this code is found inside
                turret.stopAfterNextFire = false
            end

 

Any ideas?

 

- C



[TOPIC: post.html]
#8

SegaBoy

[GLOBAL: userInfoPane.html]
SegaBoy
  • Contributor

  • 635 posts
  • Corona SDK

I'm being stupid - you mentioned pairs() you've obviously got an indexed array, so iterating backwards was never going to be relevant. 

 

When you mentioned next in the original post, I presume that's where you're now using k,v in pairs() ???



[TOPIC: post.html]
#9

Caleb P

[GLOBAL: userInfoPane.html]
Caleb P
  • Corona Geek

  • 1,424 posts
  • Corona SDK

Yep - I guess pairs() uses next() to do it's iterating.

 

- C



[TOPIC: post.html]
#10

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 26,534 posts
  • Enterprise

Is your timerStack indexed by number or by key?



[TOPIC: post.html]
#11

Caleb P

[GLOBAL: userInfoPane.html]
Caleb P
  • Corona Geek

  • 1,424 posts
  • Corona SDK

By key.

 

Actually, what I'm doing is creating random unique alphanumeric keys and pairs()-ing through them, because I'm not really sure how to use indexing. :)

 

- C



[TOPIC: post.html]
#12

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 26,534 posts
  • Enterprise

I think most people would use an integer index and use traditional for i = 1, tablesize do / end type constructs to manage those types of loops.  Key-value pairs are good when you have a natural index that's not a number, but it sounds like for what your doing the index doesn't matter.

 

You can add things to the end of a table pretty easy using the # operator (gets table length):

 

mytable[#mytable+1] = value

 

Then to remove an entry, you can use table.remove... for instance to remove the 3rd entry:  table.remove(mytable, 3).

 

And to iterate over the table (best for removing things is to go backwards):

 

for i = #mytable, 1 do

    -- do whatever

end



[TOPIC: post.html]
#13

Caleb P

[GLOBAL: userInfoPane.html]
Caleb P
  • Corona Geek

  • 1,424 posts
  • Corona SDK

And indexing like that won't have any *issues* (caused by the indexing, not the coder)?

 

- C



[TOPIC: post.html]
#14

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 26,534 posts
  • Enterprise

The only thing is deleting things from the middle of the list and using the # operator to measure the length of the array.  If you have an array:

 

x[1] = 10

x[2] = 15

x[3] = nil

x[4] = "Barney"

x[5] = "Wilma"

 

Then #x returns 2.  The nil stops the counting.  There are two solutions.  One is to use table.maxn(x) to get the actual count of records and when iterating over it, skip the nil's or two: table.remove(x, 3) to remove the entry.  The later will copy  4 to 3, 5 to 4 to collapse out the hole, so it can be a bit time consuming if you have 100,000 times and you remove #4 for instance.  

 

Of course if you use table.maxn() and you iterate over a list of 100,000 that 90% of them have been removed, that can be inefficient too.   So a combination of the two, use maxn() and then periodically purge the nil's and get a new maxn()




[topic_controls]
 
[/topic_controls]