Bug when modifying for loop objects?

49 views
Skip to first unread message

Will Maynard

unread,
Sep 29, 2015, 2:25:16 PM9/29/15
to Haxe
Hey guys,

I hit a confusing bug in my application, but after discovering what it was, I began to wonder if it's a bug with Haxe.

There are two different structures for for loops (coming from C#, I still call them "for" and "foreach" loops.  With the standard for loop, one can edit the values of the loop object just fine.  When modifying values in a "foreach" structure, however...

There is no syntax error or crash when modifying a value.  In fact, we can use the modified value as long as we're still inside the loop.  As soon as the loop ends, however, the objects are reverted to their original state.

var editMe:Array<Int>;
editMe = [1, 2, 3, 4, 5];

for (i in 0...editMe.length)
editMe[i] *= 10;
trace(editMe); // Expected: [10,20,30,40,50] | Actual: [10,20,30,40,50]

editMe = [1, 2, 3, 4, 5];
for (i in editMe)
{
i *= 10;
trace(i); // Prints 10, 20, 30, 40, 50, so we are, in fact, modifying the values.
}
trace(editMe); // Expected: [10,20,30,40,50] | Actual: [1,2,3,4,5]

To make matters more confusing, we can add and remove elements from the loop object in both structures, and the changes persist beyond the scope of the loop.

editMe = [1, 2, 3, 4, 5];
for (i in 0...editMe.length)
if (editMe[i] == 3)
editMe.remove(editMe[i]);
trace(editMe); // Expected: [1,2,4,5] | Actual: [1,2,4,5]

editMe = [1, 2, 4, 5];
for (i in editMe)
if (i == 3)
editMe.remove(i);
trace(editMe); // Expected: [1,2,4,5] | Actual: [1,2,4,5]

Is this really counter-intuitive or is it just me?

Raoul Duke

unread,
Sep 29, 2015, 2:28:09 PM9/29/15
to haxe...@googlegroups.com
> Is this really counter-intuitive or is it just me?

seems odd to me at first blush.

Max

unread,
Sep 29, 2015, 3:19:08 PM9/29/15
to Haxe
Second loop is using a copy of the value stored in Array. In both cases. I don't know what is not clear here.

Juraj Kirchheim

unread,
Sep 29, 2015, 3:40:17 PM9/29/15
to haxe...@googlegroups.com
It is wrong to say that objects are reverted to their original state. You can print editMe in the loop body and you will see it does not change.

Is this surprising to you?

  var i = editMe[0];
  trace(editMe[0]);//1
  trace(i);//1
  i *= 10;
  trace(i);//10
  trace(editMe[0]);//1

The `i in editMe` loop is really a shorthand for this code:

  //the following lines are the result of the loop head
  var iterator = editMe.iterator();
  while (iterator.hasNext()) {
    var i = iterator.next();
    //and now comes the loop body
    i *= 10;
    trace(i);
  }

Does that make things clearer?

Best,
Juraj

--
To post to this group haxe...@googlegroups.com
http://groups.google.com/group/haxelang?hl=en
---
You received this message because you are subscribed to the Google Groups "Haxe" group.
For more options, visit https://groups.google.com/d/optout.

Max

unread,
Sep 29, 2015, 3:41:46 PM9/29/15
to Haxe
Second example, second loop: array is missing value 3, therefore loop is doing nothing. If you add value 3 to array, you will still get [1,2,4,5], because you are not removing elements from the loop object as you stated. You are removing elements from the object beyond the scope of the loop.


Dana utorak, 29. rujna 2015. u 20:25:16 UTC+2, korisnik Will Maynard napisao je:

Raoul Duke

unread,
Sep 29, 2015, 3:45:49 PM9/29/15
to haxe...@googlegroups.com
> It is wrong to say that objects are reverted to their original state.

yeah, for me the main problem is when people say "object" and don't
distinguish between primitives / value types, vs. object / reference
types.

Justin L Mills

unread,
Sep 29, 2015, 3:57:31 PM9/29/15
to haxe...@googlegroups.com
Will

It's down to 'by reference' and 'by value', if you had looped over sprites adjusting the x position you would get a result more like you expect.

for( i in sprites ) i.x += 10;

In Haxe and most languages, basic types are passed by value while classes and objects are passed by reference ( and when I say pass I also mean return ).

Maybe do some googling on the subject and it will become clearer, but if you know anything about c it's kind of like the difference between a value and a pointer, although I don't know much about c so someone will step in and say I am explaining it wrong :) but hopefully it will help it click.


Best


Justin
--

Will Maynard

unread,
Sep 29, 2015, 6:58:22 PM9/29/15
to Haxe
Hey Justin,

Thanks for the help.  I didn't realize what was going on until I read your post and Juraj's.

I removed my custom objects from my MWE and replaced them with an array of integers, and I'm surprised I didn't catch it while in the middle of my post.  I've been using for loops in this fashion for months, but never used them on primitive values until last week, so I had grown accustomed to "by reference" coding.

Combine that with the fact that my old mistress, C#, would appear to even pass primitives by reference in "foreach" loops, and I can see where I was lost.

The following C# code does not compile to prevent ambiguous coding:

editMe = new int[] { 1, 2, 3, 4, 5 };
foreach (int i in editMe)
i *= 10; // Error: Cannot assign to 'i' because it is a 'foreach iteration variable'.
trace(editMe);   // Custom function to print array as [1,2,3,4,5].

Thanks again,
Will
Reply all
Reply to author
Forward
0 new messages