There is one important things to note about foreach and while loops, namely the localization of the loop variable.

The foreach loop will always localize its loop variable (That is $_ unless one is spesified). This can easily be verified:

$_ = 42; foreach (1, 2, 3) { print "Inside loop: \$_ = [$_]\n"; } print "Outside loop: \$_ = [$_]\n";
This will print
Inside loop: $_ = [1]
Inside loop: $_ = [2]
Inside loop: $_ = [3]
Outside loop: $_ = [42]
The while loop however, does not localize anything. This can be seen from the following example
$_ = 42; while(<FH>) { print "Inside loop: \$_ = [$_]"; } print "Outside loop: \$_ = [$_]\n";
If <FH> produces three lines containing the digits 1, 2 and 3 the output will be
Inside loop: $_ = [1]
Inside loop: $_ = [2]
Inside loop: $_ = [3]
Outside loop: $_ = []
It will also produce a warning if you remembered to turn on the -w flag. Why the warning you might ask. The reason is because the <FH> will return undef when it has reached the end of the file, and $_ is assigned this undef. And as we all know, perl will warn us if we use an undefined value (if the -w flag is used).

So then, what is it that happens in your program ? First, let's just simplify it a little bit (concentrating on the first foreach loop):

foreach (@test_array) { print qq|Before while: [$_]\n|; open(IN, $0) || die "No file: $!\n"; while (<IN>) { } close IN; print qq|After while: [$_]\n|; }
Now, what happens is that the foreach loop creates spesial references into the @test_array. (Spesial in the sense that when you change $_, you also change the corresponding element in the @test_array)

The next line should then print out the value of $_, which in your example would be "Element1". Then we open ourself, and loop over each line in the file. The while (<IN>) construct implicitply assigns the $_ without first localizing it. Thus we actually change the elements of the array @test_array.

If you instead had used a foreach loop to iterate over the file, this problem would not have occured, because of the fact that it would have localized the $_ variable for you. Or you could localize $_ yourself by writing local $_. Another possible solution is to use lexical variables both in the foreach loop and in the while loop

foreach my $elem (@test_array) { open(IN, $0) || die "No file: $!\n"; while( defined(my $line = <IN>) ) { } close IN; }
(The defined test isn't really necessary in newer perls, but I like to be explicit here).

"But", I hear you complain, "my while loop is in a different function, a completly new scope". Well, that is correct if you are talking about lexical scoping (variables declared with the my keyword are lexical variables). However, $_ is a dynamically scoped variable (this fact you can't change, you can't declare my $_. Here is a good tutorial explaining the difference between a lexical scope and a dynamic scope.) However, since $_ is dynamically scoped, it will live on in the new function only to be assigned by the while loop.

I hope this shed some light on the problem at hand.

Autark.


In reply to Re: What Is Going On Here ????? by autark
in thread What Is Going On Here ????? by orthanc

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.