http://qs321.pair.com?node_id=285374


in reply to array confusion

In loops like this, Perl does some magic that other popular programming languages generally do not. For folks who come from other languages or are not familiar with this magic, it can be surprising, and often in negative ways.

You might normally think that the value of each element in the list is copied to the loop variable ($item in this case). In fact, the loop variable becomes a synonym for the elements of the list. This means that if you modify the loop variable, it will modify the object inside the list to which it is currently referencing.

To be even more specific, this only applies when the list element currently being processed is an "lvalue" (fancy language for "something that can be modified"). So, if the code is

foreach my $item ($a, 2, $c) { $item = 1; }
then $a and $c will be set to 1, but the constant "2" will be copied into $item, $item will be changed to 1 and the constant "2" will be left alone.

This is why your first code sample works the way that you want it to. You have listed the actual variables you want to modify inside the foreach loop.

In your second sample, you are first copying the values in your variables into a new array and using that array in the loop. Now, you're modifying the elements of the array inside the loop and not the original variables.

Another place where this type of synonym behavior works is in calls to subroutines. The elements of @_ are actually referencing the variables of the caller's parameters (where they are lvalues). Most of the time we tend to copy @_ elements into local variables; modifying those will not modify the caller's data.

But I ramble.

-- Eric Hammond