Wednesday, February 14th, 2007

Category: FlashCategory: Flex

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.

18 Responses to 'AS3 Tip: for loop index should not be uint'

Subscribe to comments with RSS or TrackBack to 'AS3 Tip: for loop index should not be uint'.

  1. Rob | Wednesday, February 14th, 2007 | 4:37 pm

    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.]

  2. Derek Vadneau | Wednesday, February 14th, 2007 | 4:53 pm

    I tried this:
    trace(uint.MAX_VALUE);
    trace(uint.MAX_VALUE.toString());

    Both display 4294967295. The string equivalent shouldn’t be -1.

  3. senocular | Wednesday, February 14th, 2007 | 6:13 pm

    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.

  4. Keith Peters | Wednesday, February 14th, 2007 | 6:19 pm

    Yup, ran across this one a while back.

    http://www.bit-101.com/blog/?p=908

  5. George | Wednesday, February 14th, 2007 | 6:35 pm

    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.

  6. Peter | Wednesday, February 14th, 2007 | 7:56 pm

    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.

  7. vijay | Thursday, February 15th, 2007 | 4:47 am

    Maybe you can look here for some insight.

    http://vijayram.wordpress.com/2007/02/04/integer-overflow/

  8. Derek Vadneau | Thursday, February 15th, 2007 | 11:21 am

    @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.

  9. senocular | Thursday, February 15th, 2007 | 2:00 pm

    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. :)

  10. Derek Vadneau | Thursday, February 15th, 2007 | 2:15 pm

    Huh. Well, now I know. Thanks for the explanation. Not intuitive but expected. I’ll definitely keep that in mind.

  11. Theo | Thursday, February 15th, 2007 | 4:05 pm

    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.

  12. Derek Vadneau | Thursday, February 15th, 2007 | 4:24 pm

    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.

  13. fleecie | Wednesday, June 13th, 2007 | 3:48 pm

    maybe I’m totally missing something (ie the point) but why type a loop as uint, wouldn’t int be more appropriate?

  14. Derek Vadneau | Wednesday, June 13th, 2007 | 4:15 pm

    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.

  15. ivan | Friday, July 6th, 2007 | 2:17 pm

    thanks

  16. Ben | Thursday, December 20th, 2007 | 8:03 pm

    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

  17. Derek Vadneau | Friday, December 21st, 2007 | 11:00 am

    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/

  18. Gaspy | Friday, May 8th, 2009 | 9:07 am

    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.

Leave a Reply

If this is your first comment it will need to be approved before it will appear.