3

While recently trying to get one algorithm for "Getting indices of matching parentheses". I can get what that algorithm means although with some problems with perl language.

The perl syntax is not obscure and can be got much with man perl... doc.

But I am a bit confused about my behavior with for loop. man perlsyn says:

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 for non C-style loops.

I know that "non C-style loops" mean those not like for (...;...;...){...}.

The 1st sentence can be shown by this which is similar to the example shown in the doc:

$i = 'samba';
# If the variable is preceded with the keyword "my", then it is lexically scoped, and is therefore visible only within the loop.
for (my $i = 1; $i <= 4; $i++) {
  print "$i\n";
}
print "$i\n";
# 1
# 2
# 3
# 4
# samba

But I can't understand what the 2nd means:

$inner = 'samba';
for ($i = 1; $i <= 4; $i++) {
  $inner = $i + 1;
}
print "inner: $inner\n";
# inner: 5

Here the alleged "local" var $inner seems to modify the outside var, and the "former value" 'samba' can't be "regain"ed.

For the 3rd, we can do some small tweaks for the above example:

$inner = 'samba';
for ($i = 1; $i <= 4; $i++) {
  my $inner = $i + 1;
}
print "inner: $inner\n";
# inner: samba

This works expectedly for "instead of the global one".

How to understand my behavior in for loop, especially for the above 2nd sentence in the quote?


Follow-up clarification with choroba's answer hints: When using the correct "non C-style loop" the 1st and 2nd sentence seem to mean that whether my is used for var has the same effect. But actually it is not that case.

sub foo { print "foo: $x\n"; }

$x = 7;
for $x (1 .. 3) {  # Implicit localisation happens here.
  print "$x\n";
  print "global $::x\n";  # Prints 1 .. 3 correspondingly.
  foo(); # Prints 1 .. 3 correspondingly.
}
print $x;  # Prints 7.

$x = 7;
for my $x (1 .. 3) {  # Implicit localisation happens here.
  print "$x\n";
  print "global $::x\n";  # Always prints 7.
  foo(); # Always prints 7.
}
print $x;  # Prints 7.

This is just the difference between local and my which just means dynamic scope vs lexical scope as the top answer there shows which is also said in the doc.

A local just gives temporary values to global (meaning package) variables. It does not create a local variable. This is known as dynamic scoping. Lexical scoping is done with my ...

The 3rd sentence example can be updated based on this QA. Here sub uses global package variable for $x which won't be influenced by my $x = 7; and also the latter assignments, i.e. $x = 7; and $x (1 .. 3), for that new lexical.

sub foo { print "foo: $x\n"; }

my $x = 7;

# code block2
$x = 7;
for $x (1 .. 3) {  # Implicit localisation happens here.
  print "$x\n";
  ## difference 1
  print "global $::x\n";  # Prints nothing for $::x.
  # > it uses that variable instead of the global one
  foo(); # Prints nothing for $x.
}
# > but it's still localized to the loop.
print $x;  # Prints 7.

follow-up question for ikegami's answer:

If we prepend:

my $x = 7;
for $x (1 .. 3) {  # Implicit localisation happens here.
  print "$x\n";
  print "global $::x\n"; # Prints nothing for $::x.
  foo(); # Prints nothing for $x.
}
print $x;  # Prints 7.

to the above sub foo { print "foo: $x\n"; } ... example, then the latter $::x also can't access the latter defined global var $x = 7;. IMHO my creates one new var which should not influence that global var.

But if we define the latter defined var as our $x = 7; which is one "lexical alias to a package (i.e. global) variable" as the doc says. Then all works as before. What is the reason for that?

4
  • 1
    The example you took from "answer hints" as you say is different -- you dropped the my on that $x! Why? In general, when you don't use my but just use variables ($x = 7 etc) then they are created "global" and later behavior is different, and more complex/tricky. The answers tell you nicely to always use my -- and to have use strict; in the beginning so it forces you to declare variables (use my). Heed this crucial advice. (In case you do have my somewhere up in the code please show it in the question.) Commented Mar 7 at 21:22
  • The original examples in the question also appear to use global variables ($inner = 'samba'; etc, no my). If that is the case it throws off reasoning and discussion that follows. Always use my (unless you are utilizing the default $_); That's way better -- and clearer. Commented Mar 7 at 21:28
  • @zdim Thanks for pointing out my defect. "you dropped the my on that $x": I did that because $::x can't access that my var as stackoverflow.com/a/20992896/21294350 shows. Anyway I did that to show how the example in the reference link of the "the difference between local and my" link works. Commented Mar 8 at 2:23
  • "I did that because $::x can't ...", OK I see now what you meant (didn't get to read the code samples in your addition originally). Btw, I don't recall the last time I used global variables in my code. (But that's been stated plenty enough already :) Commented Mar 17 at 16:26

2 Answers 2

7

The non-C style is

for my $x (1 .. 10) {

And it works as documented:

my $x = 7;
for $x (1 .. 3) {  # Implicit localisation happens here.
    print $x;
}
print $x;  # Prints 7.

The documentation doesn't talk about other, non-loop variables. General rules for variable scope applies to them.

Also, get into the habit of using strict. It makes variable scope more explicit and contolled.

To localise a global variable, use local.

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

1 Comment

Thanks for your answer and the helpful links. I updated my question with my understanding based on your answer, could you help checking whether that is fine?
3

Let me start by saying you always want my except when using $_.


If the variable is preceded with the keyword "my", then it is lexically scoped, and is therefore visible only within the loop.

Demo:

our $x = 9;

sub f { say $x; }         # Accesses outer `$x`

for my $x ( 1 .. 3 ) {    # Creates a new `$x` scoped to the loop
   say $x;                # Accesses loop `$x`
   f();
}

say $x;                   # Accesses outer `$x`

Output:

1
9
2
9
3
9
9

Otherwise, the variable is implicitly local to the loop and regains its former value upon exiting the loop.

Demo:

our $x = 9;

sub f { say $x; }         # Accesses the only `$x`

for $x ( 1 .. 3 ) {       # Backs up and restores the SV associated with `$x`.
   say $x;                # Accesses the only `$x`
   f();
}

say $x;                   # Accesses the only `$x`

Output:

1
1
2
2
3
3
9

In other words, the code is functionally equivalent to the following:

use experimental qw( declared_refs defer refaliasing );

our $x = 9;

sub f { say $x; }              # Accesses the only `$x`.

{
   my \$backup = \$x;          # Backs up the SV associated with `$x`.
   defer { \$x = \$backup; }   # Restores the SV associated with `$x`.

   for my $ele ( 1 .. 3 ) {
      \$x = \$ele;             # `$x` is associated with SV from list.

      say $x;                  # Accesses the only `$x`.
      f();
   }
}

say $x;                        # Accesses the only `$x`.

Output:

1
1
2
2
3
3
9

9 Comments

Thanks for the detailed answer. "except when using $_" may be due to $_ is one global var as man perlvar says. 1. Is "Accesses only" one typo for "Accesses outer"? 2. Could you say something about the difference between our and the global variable? Please see the follow-up question I added (maybe I should post one new question for that). 3. Could you help checking whether "The 3rd sentence example can be updated: ..." part is fine?
1) No, It access the only $x that exists in that program. There is no outer and loop $x in that program, just a single $x.
2) our $x creates a lexically scoped alias to the current package's $x. Basically, it allows you to use package vars even when use strict; is used. I could have used my $x instead of our $x, but then sub f { say $x } would capture, which would greatly complicate the explanation.
there was brief experimentation with allowing my $_, which solved some problems with $_ but created more than it solved and was abandoned. perldoc.perl.org/perlexperiment#Lexical-$_
@An5Drama, Yes, in the absence of my and our, package var is the default. In the presence of my and/or our, the most recent one wins.
|

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.