Help: Removing non-current key within foreach

Bale

Minion
I just got this error:

Code:
[COLOR="#FF0000"]Removing non-current key within foreach (OCD Inventory Control.ash, line 327)[/COLOR]

That clearly refers to the following lines:

Code:
foreach key in kBayCount
	remove kbay [to][key];

My problems:
1. Why is that even an error?
2. Why is it a problem now when that code has been around for a while?
2. How am I supposed to remove items from a map?
 

lostcalpolydude

Developer
Staff member
The reason anything comes up is that the old "map modified within foreach" message came from Java and was simply passed along. A recent change was made to mafia to catch that error before Java runs into an exception so that useful line numbers could be provided.

I'm on the wrong computer to even try to figure it out right now, but maybe the new checking is being too strict, since the map being iterated over is not the same one that gets modified.
 

Veracity

Developer
Staff member
1) Because Java says it is an error. You can remove any item you want from a map unless you are currently iterating through it via foreach, in which case you can only remove the item you are looking at.
2) The new message is "early detection" of what used to, instead, cause "map modified within foreach". This runtime error occurs at the point of failure, rather than after the map has been corrupted.
3) Use remove.

Looking at your code, I can see that somewhere else in your program you are in the middle of a "foreach x in kbay" and now you are doing a "foreach key in kBayCount" and using that key to remove items from kbay.

If you want to use "kBayCount" to control which items are removed from "kbay", you're going to have to figure out a way to do that removal when you are not otherwise iterating through "kbay".
 

Veracity

Developer
Staff member
I'm on the wrong computer to even try to figure it out right now, but maybe the new checking is being too strict, since the map being iterated over is not the same one that gets modified.
The new checking is correct. You can be in the middle of iterating over multiple maps. We keep a stack of all the "slices" that you are currently iterating over - the nested "foreach" loops. When you call "remove" on a key, it sees which "slice" the key is in and if that slice is being looked at anywhere in that iteration stack, it makes sure that the item being removed is the current one - and it uses that iterator's remove() function to do the the removal. If the item being removed is not the current one, it throws the runtime expression.

Bale's program is doing something like this:

Code:
foreach x in kbay
    ...call a function which does:
    foreach key in kBayCount
        remove kbay [to][key];
 

Bale

Minion
If you want to use "kBayCount" to control which items are removed from "kbay", you're going to have to figure out a way to do that removal when you are not otherwise iterating through "kbay".

This. Thank you. This is what I was missing! I'm going to have to figure out how to do that properly.

Looking at the relevant section it is rather a mess which will not be easy to un-spaghetti.
 

Fluxxdog

Active member
If that's the problem, this is how I do it in my scripts:
First, create a copy of the map you'll be changing. Going off Veracity's example: kbay_copy
Run your foreach statement off of that. so that you'll have 'foreach x in kbay_copy'.
Now, you're not iterating through kbay, which means you're free to alter it.

Question comes to mind: Is there a quick/better way to make a copy? My method does seem a little... hackneyed, though I could never figure out why.
 
Top