Why does the following code creat an endless loop?

I'm more than a little sleepy (but the construction outside prevents sleep), so I fully expect to get a "duh" feeling after someone else looks it over. That is why I'm not reporting it as a bug yet.

Code:
	print( count( ItemList[ "Closet"]) + " Closet", "red");
	if( count( ItemList[ "Closet"]) > 0) {
		print( "Putting items into closet...", "blue");
		LoopCounter = 0;
		while( LoopCounter < count( ItemList[ "Closet"])) {
			print( ItemQuant[ "Closet", LoopCounter] + " " + ItemList[ "Closet", LoopCounter]);
			LoopCounter = LoopCounter + 1;
		}
	}

This particular piece of code produces the following output:
Code:
 > 682 Closet
 > Putting items into closet...
> 1 none
> 0 seal-clubbing club
> 0 helmet turtle
> 0 ravioli hat
> 0 saucepan
> 0 disco mask
> 0 disco ball
> 0 moxie weed
> 0 strongness elixir
> 0 magicalness-in-a-can
> 0 spicy noodles
> 0 tortoise's blessing
> 8 Kentucky-style derby
[b]CLIPPED FOR BREVITY[/b]
> 0 tiny plastic Boris
> 0 tiny plastic Jarlsberg
> 0 tiny plastic Sneaky Pete
> 0 tiny plastic Susie
> 0 Lucky Surprise Egg
> 0 maid head
> 0 none
> 0 none
> 0 none
> 0 none
> 0 none
etc...  Until I end the Java process because Mafia locks up.

I am running Mafia 13.5, on Linux if that matters (Ubuntu 9.04).

EDIT:: I should add, there isn't any reason ItemList should ever == $item[none], but that is a different problem to track down.
 
Last edited:
Yes, ItemList and ItemQuant are both maps.

And for some reason, changing that to a foreach loop stopped the infinite loop.

Now to track down the other problems...

(But why did LoopCounter never equal or exceed count( ItemList[ "Closet"]) in the original code?
 

DaMaster0

Member
I'm more than a little sleepy (but the construction outside prevents sleep), so I fully expect to get a "duh" feeling after someone else looks it over. That is why I'm not reporting it as a bug yet.

Code:
	print( count( ItemList[ "Closet"]) + " Closet", "red");
	if( count( ItemList[ "Closet"]) > 0) {
		print( "Putting items into closet...", "blue");
		LoopCounter = 0;
		while( LoopCounter < count( ItemList[ "Closet"])) {
			print( ItemQuant[ "Closet", LoopCounter] + " " + ItemList[ "Closet", LoopCounter]);
			LoopCounter = LoopCounter + 1;
		}
	}

Note: I am a new programmer and I will probably make mistakes.

Are you showing us the full code, or just part of it? Because if every time you put a new item in, the list will increase, making it one longer, and then when it puts in a new item, the process will happen again. But I know, it doesn't really explain the > 0 none part, but maybe KOL mafia messed up the closet so that it thought the nothing was an item. Idk. :/
 

Bale

Minion
I wonder what count( ItemList[ "Closet"]) is. For all we can tell (from that fragment) you made a mistake that resulted in 40000 entires in ItemList. Slip in a print("Length of ItemList: "+ count( ItemList[ "Closet"])+ ", LoopCounter: "+ LoopCounter) and you might discover something illuminating. Or maybe not.

Honestly though I'd use a foreach loop and take the counter out of there. Much tidier.

foreach x, value in ItemList["Closet"]
print( ItemQuant["Closet", x] + " " + value);
 

DaMaster0

Member
I wonder what count( ItemList[ "Closet"]) is. For all we can tell (from that fragment) you made a mistake that resulted in 40000 entires in ItemList. Slip in a print("Length of ItemList: "+ count( ItemList[ "Closet"])+ ", LoopCounter: "+ LoopCounter) and you might discover something illuminating. Or maybe not.

Honestly though I'd use a foreach loop and take the counter out of there. Much tidier.

foreach x, value in ItemList["Closet"]
print( ItemQuant["Closet", x] + " " + value);

oh you know what, that might be it! or maybe it counts the meat 2. So say if you had 15,000 meat in your closet, that would pretty much be an infinite loop.
 
Note: I am a new programmer and I will probably make mistakes.

Are you showing us the full code, or just part of it? Because if every time you put a new item in, the list will increase, making it one longer, and then when it puts in a new item, the process will happen again. But I know, it doesn't really explain the > 0 none part, but maybe KOL mafia messed up the closet so that it thought the nothing was an item. Idk. :/

Don't worry about the new programmer part, sometimes fresh eyes will see something different. (Sometimes we get caught up in our experience. ;-))

That is not the full code. The script is long, and every other part functioned fine. For reference, it is an update to my MuseumStockUp script.

The piece of code is only called once, so the map is not getting updated during the loop. Or at least there is no reason for it.

Slip in a print("Length of ItemList: "+ count( ItemList[ "Closet"])+ ", LoopCounter: "+ LoopCounter) and you might discover something illuminating.

Something like the first line of the code snippet?
print( count( ItemList[ "Closet"]) + " Closet", "red");

That produces this output: > 682 Closet




Honestly though I'd use a foreach loop and take the counter out of there. Much tidier.

foreach x, value in ItemList["Closet"]
print( ItemQuant["Closet", x] + " " + value);

I did...

And for some reason, changing that to a foreach loop stopped the infinite loop.

It still doesn't answer the question:
(But why did LoopCounter never equal or exceed count( ItemList[ "Closet"]) in the original code?
 

matt.chugg

Moderator
well seeing as you got it fixed it doesn't matter too much, to debug, stick a line in before the loopcounter increment, and print the loopcounter value, and the count(map) together.
for each item, I think thats what bale was getting out, so we can see if loopounter is incrementing, and see if count(something) has changed

I also don't see loopcounter declared...
 

xKiv

Active member
I would say that doing
Code:
	print( ItemQuant[ "Closet", LoopCounter] + " " + ItemList[ "Closet", LoopCounter]);
accessed ItemList[ "Closet", LoopCounter ], which autovivified it, increasing count( ItemList[ "Closet"]) to LoopCounter+1 ... because the counter started at 0
(looking for item #0 made sure that the map had a key for it -> at least that one key -> next time it was comparing counter 1 to count 1 and then increasing the count to 2 (by accessing item #1), and so on ...)
 

Bale

Minion
OH! Of course! If it had been a snake it would have bitten me!

Thanks xKiv. You solved the case.
 
I would say that doing
Code:
	print( ItemQuant[ "Closet", LoopCounter] + " " + ItemList[ "Closet", LoopCounter]);
accessed ItemList[ "Closet", LoopCounter ], which autovivified it, increasing count( ItemList[ "Closet"]) to LoopCounter+1 ... because the counter started at 0
(looking for item #0 made sure that the map had a key for it -> at least that one key -> next time it was comparing counter 1 to count 1 and then increasing the count to 2 (by accessing item #1), and so on ...)

So, if I'm understanding you correctly, a map (item[ string, int] ItemList, in this case ItemList[ "Closet", <variable>]) that has a static count of 682, has the count increased every time the script "looks" at one of it's assigned values from ItemList[ "Closet", 0] to ItemList[ "Closet", 681] by 1?

If that is how Mafia operates, that is fairly ridiculous.

No, I have a hard time believing that a properly declared, and populated map can be autovivified by printing it's values.
 
Last edited:

jasonharper

Developer
The fact that your int-keyed map had a count() of 682 does not imply that it had keys ranging from 0 to 681 inclusive, merely that it had 682 distinct keys. You haven't posted the code that originally populated the map, but I'm guessing that you used something other than consecutive integers as keys there - the item IDs, perhaps?

Retrieving a nonexistent key from a map does currently auto-vivify it, with the default value for its type. Presumably this is being done on the assumption that if you use a nonexistent key once, you're likely to use it more than once, and having the key actually exist may slightly speed up those subsequent lookups.
 
The fact that your int-keyed map had a count() of 682 does not imply that it had keys ranging from 0 to 681 inclusive, merely that it had 682 distinct keys. You haven't posted the code that originally populated the map, but I'm guessing that you used something other than consecutive integers as keys there - the item IDs, perhaps?

That assumption would be incorrect. It was supposed to be consecutive integers.

I say supposed to be, because after reading that accessing a non-existent key in a map, creates said key, that got me to re-evaluate the output. The listed value of ItemList[ "Closet", 0] is $item[none]. That should never have happened by my design, so it could have been because ItemList[ "Closet", 0] didn't exist.

Since the code is fixed, I have no way - nor inclination - of figuring out why that is. (Being "forced," if you will, into a foreach loop got me to re-evaluate the whole code in a manner that isn't relevant here.)

As for why Mafia creates a key when attempting to access it when it doesn't exist, that isn't as important as realising that it does.

I knew Mafia supported "auto" initialising of variables (I remember when it was introduced as a new feature) when it encountered a (previously) non-existent variable getting assigned a value.

I didn't consider that it initialised a map key upon access, both because there is no assigning going on and because there is no auto initialising of non map variables when only accessing them.
 
Last edited:

Veracity

Developer
Staff member
When you access a map, the result returned to the script must have the data type specific to that map, since that's what the script expects. If the key is not present, we return the default value for the data type. In Java, we could return null, and let the caller check that, but ASH has no concept of a "null value".

Now, accessing a non-existent key COULD generate a runtime error - sort of like an "array index out of bounds" error. But, when I first released maps, we didn't have good runtime errors, including file and linenumber, for example. We do now.

In any case, you can use "a[5] contains 6" to check whether "a[5,6]" is valid.
 
Top