Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested function call scoping and syntax

I'm attempting to call a nested recursive perl function, but I can't tack the correct syntax.

Question: What is the correct syntax to perform a recursive call for a nested function (if nested functions should be recursively called at all)?

Answer: Refer to suggested pseudocode in the accepted answer.

Here is a pseudocode snippet:

use Scalar::Util;
sub outerfunction {
  my $innerfunction = sub {
    # Do something
    innerfunction(); 
    # Do other things
  }; 
  Scalar::Util::weaken($innerfunction); 
  &$innerfunction(@_);
}; 

I've tried to invoke innerfunction as the following (with the consequential error messages):

innerfunction

Undefined subroutine &main::innerfunction

&innerfunction

Undefined subroutine &main::innerfunction

&$innerfunction

Global symbol "$innerfunction" requires explicit package name

I've also tried to declare the innerfunction as local, but receive the following:

Global symbol "$innerfunction" requires explicit package name

I don't have much experience with interpreted languages, so any incidental commentary related to memory/stack leakage/ corruption or other dangers with the above pseudocode (other than system limits on recursion) would be greatly appreciated as well.

Thanks! perl v5.10.1 running on Linux 2.6.34.7-61.fc13.x86_64

like image 515
WMX Avatar asked Dec 02 '22 23:12

WMX


2 Answers

The innerfunction() syntax is only available for subroutines that have been installed into the symbol table (such as the sub NAME {...} syntax does). You need to call your inner function as $innerfunction->() or &$innerfunction(), but where you are having trouble is with the scoping of the $innerfunction lexical.

When you declare a variable with my, the variable is in scope after that statement ends. So you need to split your declaration:

 my $innerfunction;
    $innerfunction = sub {
        ...
        $innerfunction->();
        ...
    };

To break the circular reference with weaken the usual pattern is:

use Scalar::Util;
sub outer_function {
    my $weak_ref;
    $weak_ref = my $strong_ref = sub {
        # Do something
        $weak_ref->(); 
        # Do other things
    };
    Scalar::Util::weaken($weak_ref); 
    return $strong_ref;
};

So now, as soon as $strong_ref goes out of scope, the subroutine will be garbage collected.

like image 131
Eric Strom Avatar answered Dec 21 '22 17:12

Eric Strom


sub outer_function {
    local *inner_function = sub {
        # Do something
        inner_function(); 
        # Do other things
    };
    inner_function();
};

is almost as good as the following, yet much much clearer:

use Scalar::Util qw( weaken );
sub outer_function {
    my $weak_ref;
    my $strong_ref = sub {
        # Do something
        $weak_ref->(); 
        # Do other things
    };
    weaken($weak_ref = $strong_ref);  # Avoid memory leak.
    $strong_ref->();
};
like image 45
ikegami Avatar answered Dec 21 '22 17:12

ikegami