12.5.5 A Subroutine that Returns A Reference to A Closure

12.5.5  A Subroutine that Returns A Reference to A Closure

 Now, we go back to a closure we looked at a learlier and make it a little bit more complex. In the closure definitions we have seen so far, the functions that work as closures have been defined with names and hence have been globally accessible. But, sometimes, this may not be a good idea. We may want to define such functions anonymously and return references to them to the outside world. Here, is an extension of the function listAdd1 that we discussed a short while ago.

 Program 12.21

sub makeAdder{
    my $n = $_[0];
    my $addX = sub {
                   my $x = $_[0];
                   $x + $n;
                   };
    $addX;
}

 

makeAdder has a lexically scoped variable $n that is accessible only inside it. Inside makeAdder, there is another lexically scoped scalar $addX that stores a reference to an anonymous function defined inside makeAdder. This anonymous function takes one parameter and returns the parameter after adding $n to it. Since $n is local to makeAdder and is accessible only inside makeAdder, the anonymous function whose reference is returned by makeAdder must somehow keep a value of $n available to it. The definition of this anonymous function along with the current binding of $n make a closure.

Outside the function makeAdder, we can call makeAdder with a parameter giving it the value of $n. This value of $n then becomes the value the closure returned by the call remembers. So, if we make the following two calls, the binding of $n associated with the first closure is 2 and the second 10.

 

$add2 = makeAdder (2);

$add10 = makeAdder (10);

 

Therefore, the following calls return

 

funcallS ($add2, 5)

funcallS ($add10, 3)

 

7 and 13 respectively.

We extend the makeAdder a little more in the next example. In makeAdder, the value of the remembered numerical value is set in the call to makeAdder. Once a value binding has been associated with a closure, there is no way to change that associated value. In the function makeAdderB that we give below, we can associate a new value with a closure once the closure has been defined.

 Program 12.22

sub makeAdderB {
    my $n = $_[0];
    my $addXNew = sub {
                      my $x = $_[0];
                      my $change = $_[1];
                      if (defined($change)){
                              $n = $x;
                       }
                      else{
                           $x + $n;
                      }; #else ends
                  }; #sub $addXNew ends
    print "makeAdderB ends; returns \$addXNew = $addXNew\n";
    $addXNew;
} # sub makeAdderB ends

makeAdderB takes a numerical value as parameter and assigns the local variable $n to the parameter supplied to it. It also declares a scalar $addXNew that stores the reference to an anonymous function. This anonymous function takes two parameters, the second of which is optional. The first parameter supplied in a call to the anonymous function is used to assign a value to a variable $x local to the anonymous function. The second parameter to the anonymous function, if supplied in a call, causes the anonymous function to reset the value associated with the closure initially supplied by $n. The new value associated with the anonymous function becomes the first parameter $x given in the call of the anonymous function.

Let us look at a call to makeAdderB and follow it by calls to the anonymous function that makeAdderB returns.

 

$addX = makeAdderB (1);

 

Now, $addX stores a reference to a closure. If we now make the

 

funcallS ($addX, 3)

 

it returns a value of 4. This is because the numerical value associated with the function referenced by $addX is 1 and the function referenced by $addX adds its parameter 3 to the value associated with it and returns the sum. However, if we now make the following call to the function referenced by $addX, the value associated with this anonymous function changes to 100.

 

#returns 100

&$addX (100, 1)

 

This is because we have provided a value to the second parameter to the call to the anonymous function and this causes the closure to set the value of the associated variable to 100, the first parameter to the call of the anonymous function. The call above returns 100, the new value associated with the anonymous function. Finally, the following call

 

funcallS ($addX, 3)

 

returns 103.