8

I am new to perl and was confused with perl scoping rules after I wrote below code snippet:

#!/usr/bin/perl
my $i = 0;
foreach $i(5..10){
    print $i."\n";
}
print "Outside loop i = $i\n";

I expected output to be like :

5
6
7
8
9
10
Outside loop i = 10

But its giving :

5
6
7
8
9
10
Outside loop i = 0

So the variable $i value is not changing after the loop exits. Whats going on in here?

2
  • 2
    Side note, unrelated to your problem. Since you mentioned that you're new to Perl and just in case you haven't already been hit over the head a thousand times about this: you should always put use strict; use warnings; at the top of every Perl script you write. Those two pragmas can save you a lot of painful debugging. Commented Feb 3, 2015 at 18:56
  • possible duplicate of What is the default scope of foreach loop in Perl? Commented Feb 3, 2015 at 20:52

3 Answers 3

6

According to the perldoc information regarding foreach loops: here

The foreach loop iterates over a normal list value and sets the variable VAR to be each element of the list in turn. If the variable is preceded with the keyword my, then it is lexically scoped, and is therefore visible only within the loop. Otherwise, the variable is implicitly local to the loop and regains its former value upon exiting the loop. If the variable was previously declared with my, it uses that variable instead of the global one, but it's still localized to the loop. This implicit localization occurs only in a foreach loop.

If you want to retain the value of $i outside the loop then you can omit $i in the foreach loop call and use perl's special variable $_ an example below:

#!/usr/bin/perl

use strict;
use warnings;

my $i = 0;
foreach (5..10){
    print $_."\n";
    $i = $_;
}
print "Outside loop i = $i\n";

5 6 7 8 9 10 Outside loop i = 10

Sign up to request clarification or add additional context in comments.

8 Comments

What an explanation. Exactly what I was looking for. So does this means there isn't a way of preserving foreach loop variable value after loop exits?
If this is the case, then I will need to use another variable and assign it the loop variable value in each iteration. Isn't this is inefficient and extra work.
Even if you spell foreach as for, the localization occurs. It looks like you'll need a spare variable to get the value of $i in the loop on each iteration.
@chammu it seems that you need a helper variable in regards to this, I will update my answer accordingly/
Changing from an explicitly named variable to $_ is generally considered a step backwards for maintainability. Usage of the "C style" for loop or a while loop is probably a better solution to this problem.
|
5

foreach localize variable to the loop.

use strict;
use warnings;

my $adr;
my $i = 0;
foreach $i(5..10){
    $adr = \$i;
    print "$i ($adr)\n";
}
$adr = \$i;
print "Outside loop i = $i ($adr)\n";

output

5 (SCALAR(0x9d1e1d8))
6 (SCALAR(0x9d1e1d8))
7 (SCALAR(0x9d1e1d8))
8 (SCALAR(0x9d1e1d8))
9 (SCALAR(0x9d1e1d8))
10 (SCALAR(0x9d1e1d8))
Outside loop i = 0 (SCALAR(0x9d343a0))

From perldoc,

The foreach loop iterates over a normal list value and sets the variable VAR to be each element of the list in turn. If the variable is preceded with the keyword my, then it is lexically scoped, and is therefore visible only within the loop. Otherwise, the variable is implicitly local to the loop and regains its former value upon exiting the loop. If the variable was previously declared with my, it uses that variable instead of the global one, but it's still localized to the loop. This implicit localization occurs only in a foreach loop.

To preserve value of $i you can use C like for loop,

my $i = 0;
for ($i = 5; $i <= 10; $i++) { .. }

although it's less readable than perl foreach

9 Comments

Here, I am not using foreach my $i. It that case I can expect it to localize.
But if I don't give the declaration at the top which is my $i = 0, it will complain regarding variable being not declared
Your is working example of what is mentioned in link provided by @PrgmError . Thanks.
C-style loops may be less readable, but IMO are clearer when you do want the value to persist. easy to make off-by-one errors though :)
note that the reason it is localized to the loop is that it really is aliasing the variable to each element in the list being iterated over (or emulating that, in the case of ..), not setting the existing variable to each value in turn.
|
0

The variable $i is redefined in foreach scope at

foreach $i(5..10){

So the variable outside foreach will not change.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.