jroberts has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I've been using perl for years (casually). Yesterday, by accident, I noticed that the following code
$a = ['a', 'b', 'c']; for $i (@{$a}) { undef $i; }
will actually undef all of the the elements in $a. Not what I expected... I expected that (@{$a}) would result in a list of the elements of $a and $i would take on the value of each of the elements, not a reference to the elements. If I said something like
@x = @{$a} -OR- @x = (@{$a})
@x would have the elements of $a not the refs... This seems very odd to me. Am I alone in this thinking?

Replies are listed 'Best First'.
Re: Using Array Refs
by Transient (Hermit) on May 05, 2005 at 14:25 UTC
    It's more a statement of how foreach works (you're actually using a "foreach" loop there, rather than a C-style "for" loop).

    If any element of LIST is an lvalue, you can modify it by modifying VAR inside the loop. Conversely, if any element of LIST is NOT an lvalue, any attempt to modify that element will fail. In other words, the foreach loop index variable is an implicit alias for each item in the list that you're looping over.
Re: Using Array Refs
by ikegami (Patriarch) on May 05, 2005 at 14:27 UTC

    The (explicitly stated or implicite $_) loop variable in foreach loops is always an alias (what Perl calls C-like references) to the element, as opposed to a copy. This has nothing to do with a reference ($a) being involved. If you want to modify the loop variable without modifying the array element, use one of the following workarounds:

    foreach (@array) { my $i = $_; # $i is a copy. ... }

    or

    foreach (@array) { local $_ = $_; # $_ is a copy. ... }
Re: Using Array Refs
by polettix (Vicar) on May 05, 2005 at 14:26 UTC
    for makes $i an alias for the relevant scalar in the array at each iteration. See perldoc perlsyn among the others.

    Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')

    Don't fool yourself.
Re: Using Array Refs
by gellyfish (Monsignor) on May 05, 2005 at 14:40 UTC

    Nope it's documented - see perlsyn:

    If any element of LIST is an lvalue, you can modify it by modifying VAR inside the loop. Conversely, if any element of LIST is NOT an lvalue, any attempt to modify that element will fail. In other words, the foreach loop index variable is an implicit alias for each item in the list that you're looping over.

    That the "list value" is a de-referenced array ref doesn't make any difference here - the elements are still lvalues

    /J\

Re: Using Array Refs
by danielcid (Scribe) on May 05, 2005 at 14:47 UTC
    You are confusing the things a little bit. When you do @x = @{$a} you are "copying" the content of "@{$a}" to "@x". With foreach, you are just passing a reference to it...
    If you don' wanna mess with your original array, you need to copy it to a second array (like you did @x=@{$a}) and use @x ...
    @x = @{$a}; foreach my $i (@x) { print"$i\n"; undef $i; }
    or as someone suggested before:
    my $a = ['a', 'b', 'c']; foreach (@{$a}) { my $i = $_; print"$i\n"; undef $i; }