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

in reply to NEWBIE Brain Teaser

Now that the cat's out of the bag, I'll share the explanation I had written up...a bit more long winded:

HOW THE CODE WORKS

So what's going on here? At first glance, this bit of code seems pretty straightforward. Line 1 assigns numbers 1 thru 5 to the first 5 elements of the @list array. Lines 3-6 do nothing but declare variables. The foreach loop starting on line 8 assigns each element of @list to \$each and multiplies the contents of \$each by two. It then assigns each \$each to an element of the @newlist array. Finally, the for loop starting on line 14 simply steps through each element of both the @newlist and @list arrays simultaneously and subtracts one array from the other. You would expect the first iteration of the for loop to be 2-1 yielding "1", the next iteration to give 4-2 yielding "2", and so on. So what's the problem here?

The answer lies in the first statement of the foreach block, \$each *= 2;. What happens is that the @list array gets aliased through the \$each variable. What does this mean? It means that whatever you do to the \$each variable in the foreach loop, you also do to the corresponding element of the @list array. So, for example, when \$each is equals "3" and it gets multiplied by "2", the third element of @list gets multiplied by "2", too, setting it's value to "6". And there you have the reason why the output of this code is nothing but 5 zeroes!

Replies are listed 'Best First'.
Re: Re: NEWBIE Brain Teaser
by Ri-Del (Friar) on Apr 15, 2001 at 08:04 UTC

Alright, I also expected a return of 1,2,3,4, and 5 as the values printed out. However, I think I have learned where I went wrong. I just wanted to make sure I understood the last paragraph of HOW THE CODE WORKS.

If I understand this correctly, the \$each variable actually acts as a reference to the current place in the array that the foreach loop is currently at. So in effect we are actually altering the first array with the \$each *= 2; and then simply setting the \$i place in the @newlist to be the same value. This is the reason why we are subtracting, in the last loop, the exact same values from each other.

Yes, although I do not know if "referencing" is the accurate term. As the post above mine pointed out, the book "Learning Perl" uses the term alias. How that is different from referencing, I'm not entirely certain and maybe a more monkish Monk than I could answer that.
Explicit referencing requires an explicit dereference. Aliasing is intended to mean something much more transparent.
i am not a "more monkish Monk", but i did get curious about this behavior of foreach. This is an alias (example modified from _Advanced Perl Programming_ (O'rielly) by Sriram Srinivasan):
```\$a = 10;         # saclar a
@a = (1, 2, 3);  # array a
*b = *a;         # aliases b to a

\$a++;            # increments \$a :)
\$b++;            # same as saying \$a++
print "\$b, \$a";  # prints: 12 12

@b = 4;       # same as saying \$a = 4