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

i am new to perl, i have a simple doubt, can i change the length of the array while using foreach loop, and can i shift or push elements into the array? if i shift the elements inside the array which element will the loop take for the next iteration, same way what is the case when i push?

Replies are listed 'Best First'.
Re: Question on arrays
by neshura (Chaplain) on Feb 12, 2000 at 03:58 UTC
    I agree with btrott. Messing with the array elements is a Bad Idea(tm). It is absurdly easy to set up an infinite loop (or worse -- worse being subtle bugs rather than obvious bugs). I don't have a book handy, but from what I can tell by testing a few configurations, for and foreach both do implicit array operations that are, to the programmer, black-boxed. Don't mess with the box if you are new to perl.

    The code btrott posts shows the implicit behavior. $_ is shifted/unshifted in every loop. Within the second loop, 'bar' is shifted from @arr into $_; as a result, the _explicit_ shift removes baz. When the loop ends, $_ is unshifted back onto the array but 'baz' is lost forever. @arr is reduced to 'foo bar quack'.

    Of course, this could come in handy for obfuscation.

Re: Question on arrays
by japhy (Canon) on Feb 11, 2000 at 22:08 UTC
    When going through an array, a for() loop will keep track the index of the element it's at, so it knows what the next element will be.
    for (@array) { ... } # is kind of like for ($i = 0; $_ = $array[$i], $i < @array; $i++) { ... }
Re: Question on arrays
by btrott (Parson) on Feb 12, 2000 at 00:54 UTC
    According to perldoc perlsyn:
    If any part of LIST is an array, foreach will get very confused if you add or remove elements within the loop body, for example with splice. So don't do that.
    So, it seems to me, you probably don't want to be adding or removing elements while within a for loop. Was that your question?

    For example, I just tested this w/ shift. I looped through an array using foreach and did a shift part of the way through:

    my @arr = qw/foo bar baz quack/; for (@arr) { print $_, "\n"; shift @arr if $_ eq "bar"; }
    Here's the output:
    foo bar quack
    So the shift shifted off "foo", which messed up the internal loop counter, which means that "baz" didn't get displayed. So this probably isn't the best idea.