Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Re: What Is Going On Here ?????

by autark (Friar)
on Nov 21, 2000 at 22:03 UTC ( #42740=note: print w/replies, xml ) Need Help??

in reply to What Is Going On Here ?????

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.


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://42740]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2020-11-30 05:34 GMT
Find Nodes?
    Voting Booth?

    No recent polls found