Wednesday, February 14th, 2007 |
|
AS3 Tip: for loop index should not be uint |
In AS2 you probably typed your for loop index variable as Number. In AS3 I thought it would be better to use uint. I always start the index from 0, or some positive number and increment from there, like:
var i:uint;
for (i=0; i<myArray.length; i++)
{
// code
}
This worked fine for everything I did … until I created a for loop to count down. Typically you do this when removing items from an array, like:
var i:uint;
for (i=myArray.length - 1; i>=0; i--)
{
// code
}
However, if you run this code, you’ll find yourself in an endless loop. Why? When i = 0 the loop runs, then gets to the next iteration and tries to decrement i. But, because i is uint, the next value is 4294967295 (uint.MAX_VALUE).
Here’s an example of this behaviour:
var i:uint; i = 0; i = --i; trace(i) ; // 4294967295
However, the following code produces -1 in the console window:
var i:uint; i = 0; trace(--i) ; // -1
That seems like a bug to me.
In any case, you should type i as int, which would allow it to be -1 in the for loop code above.
NOTE: As I run across little tidbits I’d like to remember for later I’ll post them here for my own and everyone else’s benefit. Fell free to comment about the tips. Please don’t submit random tips. If you have a related tip, then post it. If you really want to submit a tip that I haven’t covered yet feel free to contact me and describe the tip in detail.










This might not be a bug:
var i:uint;
i = 0;
trace(- - i) ; // -1
The trace function expects a string. So it converts uint.MAX_VALUE to its
string equivalent which is also -1. The FVM just stores it as so. Of course
I could be wrong.
R.
[Edit: I edited the - - i because it was being written to the page as -i. Strange WP issue.]
I tried this:
trace(uint.MAX_VALUE);
trace(uint.MAX_VALUE.toString());
Both display 4294967295. The string equivalent shouldn’t be -1.
trace(- - i) ; // -1
is as expected. The expression is evaluated using Number precision. The value obtained by trace is the Number value of that operation before the value is recast into a unit as it’s reassigned to i.
You can get around this in your trace by using
trace(uint(- - i));
This will cast the Number value back to uint before trace gets a hold of it.
Yup, ran across this one a while back.
http://www.bit-101.com/blog/?p=908
Not a bug of course. With uint, variables wouldn’t accept negative. Just be careful to use uint. Similar situation when you are going to return an array item with a negative index.
Interesting, though if you increment in a for loop I don’t see a reason why you wouldn’t use a uint type, right?
You could also simply avoid the problem by going from myArray.length to 1 instead of length - 1 to 0.
Maybe you can look here for some insight.
http://vijayram.wordpress.com/2007/02/04/integer-overflow/
@senocular:
Not sure why this is “expected” behaviour. Are you saying that it is expected that Flash may not evaluate a type as specified? While it might be the case, I would not have expected that.
@Keith:
I read your blog when it pops up on MXNA but must have missed that one. The link to Sho’s post was something I read but forgot about. When I run into this kind of stuff I’ll make sure to check the blogs a little more closely.
@George:
I wasn’t pointing out that the uint var not going to -1 was a bug, just the tracing of the decremented value. The tip was to not use uint in this case because it can’t go negative.
@Peter:
The only problem with using length and 1 is that you have to subtract the index in the loop yourself.
@vijay:
Interesting post, thanks.
Yes this is “expected” in that ECMAScript specifies calculations and expressions be handled using floating-point numbers. The value obtained by trace is the value resulting from the expression, not i. This gives you the floating-point value prior to it being recast into a uint for the assignment back to i where the value /then/ becomes 4294967295. Maybe not intuitive, but it’s correct.
Huh. Well, now I know. Thanks for the explanation. Not intuitive but expected. I’ll definitely keep that in mind.
Counting backwards with a for loop is always a bit tricky, it too many things that can go wrong. Someone suggested setting the length of the array to zero instead, and while this works, it’s something of a hack, I think.
This is my prefered way of doing it:
while ( list.length > 0 ) {
list.pop();
}
Much more readable and more safe than the backwards for-loop.
Good warning though.
That’s really not the same thing. You’re just clearing out the array. Using an index is useful when you are removing items from the array but not necessarily everything.
I tend to think of while loops as more dangeous, since you are responible for the exit condition. The while loop has its place, but in this case it’s of no advantage. In fact you’d end up with the same scenario if you were keeping track of the index.
maybe I’m totally missing something (ie the point) but why type a loop as uint, wouldn’t int be more appropriate?
If the number is always positive, why would you use int?
In this case the index does NOT remain positive, or rather shouldn’t, so uint is not appropriate. In a positive moving index, as in my first example, the index never becomes negative so it’s fine. The problem was when the index moved in the negative direction.
thanks
I don’t understand, you’re code is designed to loop infinitely.
You *cannot* for a if( UINT = 0…
In real life, you *should* be using INT if you expect your value to become negative, or use UINT
No it’s not *designed* to loop infinitely, it just happened to work that way. As I mentioned in the post I typically used uint for loops since I was expecting the number to always be positive. In the second case it needed to go negative but didn’t because the index was of the type uint.
“In real life, you *should* be using INT if you expect your value to become negative, or use UINT”
… What? I should use INT, or use UINT? I was, that was the problem.
Anyhow, for all projects I now use Number instead of uint or int. Check out this link, originally posted in the article mentioned in the comments from Keith Peters:
http://kuwamoto.org/2006/06/15/avoid-ints-in-actionscript/
I know this is old, but I just want to add something:
uint is slow; much slower than int.
You should use uint ONLY for doing bitwide operations like RGB values and stuff. For anything else, int/Number are more appropriate.