chromatic has asked for the wisdom of the Perl Monks concerning the following question:

I'm testing a mod_perl application and seeing intermittent segfaults. I've traced at least one of these to a method that looks rather like this:
sub getWorkspace { my ($self, $WHERE, $TYPE) = @_; $TYPE = $self->getType($TYPE) if ($TYPE); sub cmpval { my ($val1, $val2) = @_; if (ref($val1) eq 'Node') { $val1 = $$val1{node_id}; }; if (ref($val2) eq 'Node') { $val2 = $$val2{node_id}; } $val1 eq $val2; } foreach my $node (keys %{ $this->{workspace}{nodes} }) { my $N = $this->getNode($node); my $match = 1; foreach (keys %$WHERE) { $match = 0 unless cmpval($$N{$_}, $$WHERE{$_}); } push @results, $N if $match; } return \@results; }
Now mod_perl uses eval() tricks to compile the whole application into a handler subroutine, so all of the top-level sub declarations will be at least one level lower.

My question is, am I right to be suspicious of the inner subroutine (cmpval())? Is there a limit as to how far you can nest these things before you run into a stack limit?

It's easy enough to move the inner sub outside, or create an anonymous sub out of it. Can anyone confirm my suspicions?

Replies are listed 'Best First'.
(tye)Re2: Inner Subroutines, mod_perl, and Segfaults
by tye (Sage) on Jan 25, 2001 at 23:59 UTC

    If you really want a "local" subroutine, you write:

    { my $cmpval; BEGIN { $cmpval= sub { my ($val1, $val2) = @_; if (ref($val1) eq 'Node') { $val1 = $$val1{node_id}; }; if (ref($val2) eq 'Node') { $val2 = $$val2{node_id}; } $val1 eq $val2; }; } sub getWorkspace { # ... $match = 0 unless &$cmpval($$N{$_}, $$WHERE{$_}); # ... } }
    FYI.

            - tye (but my friends call me "Tye")

      ...and, of course, this won't work at all well under mod_perl. ):

              - tye (but my friends call me "Tye")

        ...but, of course (5 years later), it is easy to make this work well under mod_perl:

        BEGIN { my $cmpval= sub { my( $val1, $val2 )= @_; if( ref($val1) eq 'Node' ) { $val1= $val1->{node_id}; } if( ref($val2) eq 'Node' ) { $val2= $val2->{node_id}; } return $val1 eq $val2; }; sub getWorkspace { # ... $match= 0 if ! $cmpval->( $N->{$_}, $WHERE->{$_} ); # ... } }

        - tye        

(tye)Re: Inner Subroutines, mod_perl, and Segfaults
by tye (Sage) on Jan 25, 2001 at 23:38 UTC

    Um, sub declarations don't really nest. You could move the "sub cmpval" out from within the "sub getWorkspace" and the code would look more like how Perl actually interprets it.

    Is that even close to what you are wondering about?

            - tye (but my friends call me "Tye")
      So there's a difference between named subs and anonymous subs (closures)?

      A named sub declared at any point in a package (even inside an eval()) gets installed into the symbol table.

      I guess this test shows the difference, not that I'd do this in practice:

      sub do_this { my $arg = shift; my $foo = "bar"; sub do_that { print "Arg is: $arg!\n"; print "Foo is: $foo!\n"; } } do_this(1); do_that();
      We get the ever-popular "variable will not stay shared" message familiar to mod_perl hackers.

      Thanks for the clarification.

        Yes, there is a difference. I tried to explain the why's and wherefore's of it in RE (3): BrainPain-Help. (And yes, I am still looking for feedback on whether that explanation made sense to anyone...)
Re: Inner Subroutines, mod_perl, and Segfaults
by MeowChow (Vicar) on Jan 27, 2001 at 00:05 UTC
    my ($self, $WHERE, $TYPE) = @_; ... foreach my $node (keys %{ $this->{workspace}{nodes} }) {
    Are you sure that you mean to be using $this instead of $self in the foreach loop?