0

Here is the first example:

$g=5;
sub A {
    my  $x=2;    # $x uses static scoping
    local $y=3;  # $y uses dynamic soping
    local $g=7;
    print "In A: g=$g, x=$x, y=$y\n";
    B();
}

sub B {
    print "In B: g=$g, x=$x, y=$y\n";
    C();
}

sub C {
    print "In B: g=$g, x=$x, y=$y\n";
}

A();
print "In main: g=$g, x=$x, y=$y\n";

Here is the output of first example:

In A: g=7, x=2, y=3
In B: g=7, x=, y=3
In B: g=7, x=, y=3
In main: g=5, x=, y=

Here is the second example:

sub big {
    my $var=1;
    sub sub1 () {
    print "  In sub1 var=$var\n";
    }
    sub sub2 () {
        $var = 2;
    print "In sub2, var is $var\n";
        sub1();
    }
    sub1();
    sub2();
    sub1();
}

big();

Here is the second output:

  In sub1 var=1
In sub2, var is 2
  In sub1 var=2
  In sub1 var=2

The question is: Why in the second example sub B and sub C can acess to my $x=2; while in the first example sub1() and sub2() can't acces to my $var=1; I believe my used for static scoping, also there is no any other $x in static scope of sub big in example 2, I expected no output in the second example, like this: In sub1 var=.How in the second example,can sub1 and sub2 can acces to $x altough it has declared with the word my, why does it not behave like the first example?

BoraKurucu
  • 39
  • 1
  • 1
  • 8
  • 1
    I suggest that you review your text at the end -- it mixes up examples and variables in them, making it (even) harder to understand what you are asking. Can you clean that up? ("_the second example ... can access `$x`_" --- no, that variable is from the first example ... etc ...) – zdim Nov 15 '19 at 10:43

2 Answers2

2

All lexical variables (one declared with my) is only visible inside its innermost enclosing block of code. A block of code is either a list of statements surrounded by { ... } or a code file.

In your first example, the subroutines are all defined at the top level of your file. The code blocks that define the subroutines are all completely separate and any lexical variable declared within one of those subroutines will not be visible in any of the others.

In your second example, you define the subroutines sub1() and sub2() inside the subroutine big(). This means that the code blocks that define the two inner subroutines are within the code block that defines the outer subroutine - and, therefore, the two inner subroutines can see any lexical variables that are declared in big() (because those variables are visible anywhere within big()'s code block).

Dave Cross
  • 68,119
  • 3
  • 51
  • 97
  • 4
    Re "*the two inner subroutines can see any lexical variables that are declared in big()*", Named subs capture at compile-time, so the inner sub sees the `$var` that existed at compile-time. If you call the outer sub multiples times, you could have problems. That's why the code produces two `Variable "$var" will not stay shared` warnings. – ikegami Nov 15 '19 at 11:12
1

The scope of lexical (my) variables (i.e. from where they can be seen/accessed) is defined by the inner-most block (curlies) or file in which they are located.

$ perl -e'
   use strict;
   use warnings;

   my $x = 123;
   {
      my $x = 456;
      print "$x\n";
      # The second $x can only be seen up to here.
   }

   # It is as is the second $x never existed here.
   print "$x\n";
'
456
123

The fact that the inner block is part of a sub declaration isn't any different.

That said, do not place named subs inside of named subs.

First of all, it doesn't make them private.

$ perl -e'
   use strict;
   use warnings;

   sub outer {
      sub inner { print "inner\n"; }
   }

   inner();
'
inner

More importantly, it will result in lots of weird behaviour.

$ perl -e'
   use strict;
   use warnings;

   sub outer {
      my ($x) = @_;
      sub inner { print "inner $x\n"; }
      print "outer $x\n";
      inner();
   }

   outer(123);
   outer(456);
'
Variable "$x" will not stay shared at -e line 7.
outer 123
inner 123
outer 456
inner 123

Named subroutines capture at compile time, so inner captures the $x that exited at compile-time. When outer exits, its $x is replaced with a fresh $x breaking the connection between outer's $x and inner's.

This is exactly why you must ALWAYS use use strict; use warnings;.

If you want a private inner sub, use an anonymous sub instead; they capture at runtime.

$ perl -e'
   use strict;
   use warnings;

   sub outer {
      my ($x) = @_;
      my $inner = sub { print "inner $x\n"; };
      print "outer $x\n";
      $inner->();
   }

   outer(123);
   outer(456);
'
outer 123
inner 123
outer 456
inner 456

There is also an experimental feature you can use.

$ perl -e'
   use strict;
   use warnings;
   use experimental qw( lexical_subs );

   sub outer {
      my ($x) = @_;
      my sub inner { print "inner $x\n"; }
      print "outer $x\n";
      inner();
   }

   outer(123);
   outer(456);
'
outer 123
inner 123
outer 456
inner 456
ikegami
  • 367,544
  • 15
  • 269
  • 518