GuidesThe Perl You Need to Know, Part II: Working with Nested Subroutines...

The Perl You Need to Know, Part II: Working with Nested Subroutines Page 5

ServerWatch content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.




Now you understand that there are cases where your normal subroutines can
become inner, since if your script was a simple:

  simple.pl
  ---------
  #!/usr/bin/perl 
  sub hello { print "Hello" }
  hello();

Wrapped into a run() subroutine it becomes:

  simple.pl
  ---------
  package cache::simple_2epl;
  
  sub run{
    #!/usr/bin/perl 
    sub hello { print "Hello" }
    hello();
  }

Therefore, hello() is an inner subroutine and if you have used
my() scoped variables defined and altered outside and used
inside hello(), it won't work as you expect starting from the
second call, as was explained in the previous section.

Remedies for Inner Subroutines

First of all, there is nothing to worry about, as long as you don't forget
to turn the warnings On. If you do happen to have the "my()
Scoped Variable in Nested Subroutines"
problem, Perl will always alert you.

Given that you have a script that has this problem, what are the ways to
solve it? There are many of them and we will discuss some of them here.

We will use the following code to show the different solutions.

  multirun.pl
  -----------
  #!/usr/bin/perl -w
  
  use strict;
  
  for (1..3){
    print "run: [time sh]n";
    run();
  }
  
  sub run{
  
    my  = 0;
  
    increment_counter();
    increment_counter();
  
    sub increment_counter{
      ++;
      print "Counter is equal to  !n";
    }
  
  } # end of sub run

This code executes the run() subroutine three times, which in
turn initializes the variable to 0, every time it is executed and then calls the inner
subroutine increment_counter() twice. Sub
increment_counter() prints 's value after incrementing it. One might expect to see the following
output:

  run: [time 1]
  Counter is equal to 1 !
  Counter is equal to 2 !
  run: [time 2]
  Counter is equal to 1 !
  Counter is equal to 2 !
  run: [time 3]
  Counter is equal to 1 !
  Counter is equal to 2 !

But as we have already learned from the previous sections, this is not what
we are going to see. Indeed, when we run the script we see:

  % ./multirun.pl

  Variable "" will not stay shared at ./nested.pl line 18.
  run: [time 1]
  Counter is equal to 1 !
  Counter is equal to 2 !
  run: [time 2]
  Counter is equal to 3 !
  Counter is equal to 4 !
  run: [time 3]
  Counter is equal to 5 !
  Counter is equal to 6 !

Obviously, the variable is not reinitialized on each execution of run(). It
retains its value from the previous execution, and sub
increment_counter() increments that.

One of the workarounds is to use globally declared variables, with the
vars pragma.

  multirun1.pl
  -----------
  #!/usr/bin/perl -w
  
  use strict;
  use vars qw();
  
  for (1..3){
    print "run: [time sh]n";
    run();
  }
  
  sub run {
  
     = 0;
  
    increment_counter();
    increment_counter();
  
    sub increment_counter{
      ++;
      print "Counter is equal to  !n";
    }
  
  } # end of sub run

If you run this and the other solutions offered below, the expected output
will be generated:

  % ./multirun1.pl
  
  run: [time 1]
  Counter is equal to 1 !
  Counter is equal to 2 !
  run: [time 2]
  Counter is equal to 1 !
  Counter is equal to 2 !
  run: [time 3]
  Counter is equal to 1 !
  Counter is equal to 2 !

Get the Free Newsletter!

Subscribe to Daily Tech Insider for top news, trends & analysis

Latest Posts

Related Stories