12.5.1 When Can Closures Occur?

12.5.1  When Can Closures Occur?

  We now see when closures can occur in Perl. We examine two situations: closures in the main program, and closures inside subprograms.

The following is a closure that can occur in the main program.

 Program 12.16

my $n = 10;

sub addN{
    return $_[0] + $n;
}

#prints 210
print addN (200), "\n";

 

Here, we have a lexical my variable called $n in the main program. We next define a function called addN that takes one parameter and returns this parameter with $n added to it. Note that $n is not a variable that is bound inside addN.

This is a very simple case and not very interesting. The more interesting case occurs when we define functions inside functions and when such a function inside a function is an anonymous function. Let us see a few examples of functions inside functions.

 Program 12.17

sub fiveAdds{
   
    my $m = $_[0];

    sub add1{
        return $_[0] + 1;
    }
    
    my $add3 = sub{
        return $_[0] + 3;
    };

    $add4 = sub{
        return $_[0] + 4;
    };

    $addM1 = sub{
        return $_[0] + $m;
    };

    my $addM2 = sub{
        return $_[0] + $m;
    };

    return add1($_[0]) * &$add3($_[0]) * &$add4($_[0]) * 
               &$addM1 ($_[0]) * &$addM2 ($_[0]);

}

print fiveAdds (2), "\n";

#note add1 and add2 have become functions that are available globally
print add1 (21) * add2 (23), "\n";

#note &$add3 is not available outside the subprogram
#note &$add4 is available outside the subprogram
print add1 (2) * add2 (2) * &$add4(2), "\n";

 

We define a subprogram called fiveAdds. Inside fiveAdds, we declare and assign a lexically scoped or my variable called $m. We then define five different functions that perform addition. Let us look at function add1 first. add1 takes a scalar parameter (which is different from the scalar parameter that fiveAdds takes) and adds 1 to it. Even though add1 is defined inside fiveAdds, add1 becomes a globally defined function. It can be seen and called outside fiveAdds.

Next, we define four more functions. These functions are anonymous functions. References to these functions are stored in the scalars $add3, $add4, $addM1 and $addM2 respectively. $add4 is a globally scoped scalar and as a result, the function that is referenced by $add4 is seen and can be called outside the containing subprogram fiveAdds. The function referenced by $addM1 is similar. However, the scalars $add3 and $addM2
are declared using my and hence are lexically scoped inside fiveAdds. They are not seen and therefore, the functions they reference cannot be called outside the textual body of fiveAdds. Of course, all five functions are seen and can be called inside the containing function fiveAdds.

The functions referenced by $add3 and $add4 are not much different from the function add1 except that the last two functions are defined anonymously and hence have to be referenced using scalar references. However, the last function $addM2 is a bit different. It is referenced using a lexically scoped scalar: $addM2. Inside the body of the function, we use a scalar $m that is defined outside and bound to a value outside the definition of the function. The function referenced by $addM2 cannot be called outside the body of the function fiveAdds. But, because it is referenced by a scalar, the scalar reference can be returned by the function fiveAdds if it so chooses. Nothing is done with these two function referencing scalars in the function fiveAdds, but we see next that this function can behave as closure also if their references are returned to the outside world by the containing function. The first three functions cannot behave as closures.