in reply to Re: Re: Re: Re: Re^3: Perl to Ruby translator?
in thread Perl to Ruby translator?

Who said this was in a loop? This is a CGI script, which exhibits this problem when run in any persistent environment like mod_perl, PerlEx, etc. These are a very common target for Perl code, so this comes up all the time. I have helped several people with this exact problem on PerlMonks, and many more on the mod_perl list. They never believe me when I tell them it's a closure.

It happens in other situations too, but this is the most common one I've seen.

  • Comment on Re: Re: Re: Re: Re: Re^3: Perl to Ruby translator?

Replies are listed 'Best First'.
Re: Re: Re: Re: Re: Re: Re^3: Perl to Ruby translator?
by BUU (Prior) on Oct 11, 2003 at 18:47 UTC
    Well, now I understand the mechanics behind it becoming a closure, but why on earth would perl make it a closure? That doesn't make any sense to me. Why wouldn't the sub just use whatever $q it can find in the closest scope to it?

      That's exactly what makes it a closure.

      Lexical variables live in their own symbol tables (that's not what they're called in Perl 5, but it's the concept: just a mapping of a name to the data structure that represents the appropriate variable container). They nest — that's why you can write code like this:

      my $foo = 'outside'; { my $foo = 'inside'; print "Inside: '$foo'\n"; } print "Ouside: '$foo'\n";

      If you dump the optree with something like B::Concise, you'll see enter, leave, and pad operations. The enter and leave ops govern which symbol table (scratch pad or lexical pad, in Perl 5 terms) is active. Think of it like a stack and you'll get it. The pad operations look up a symbol in the scratch pad.

      Subroutines (anonymous and named) are represented by data structures called CVs (basically, Code Values). Every CV is attached to a lexical symbol table. That's just a place to store the lexical variables declared and used within that subroutine.

      To handle the nesting issue, there has to be a way to look outward from inner scopes. If there's no $foo in the tightest, most innermost scope, look outward, one scope at a time, to find the nearest appropriate $foo. (This is complicated a little bit by global variables, which are handled with a different symbol table implementation in Perl 5. There also appears to be variable analysis because of the pad ops, not glob ops. Insert handwaving here; I really don't want to read that code right now.)

      The code example you're asking about is a closure so that nested variable scopes will work. Or, put the way it actually happened, because nested variable scopes had to work, closures were possible.

      It is not a problem when run as is, because it does not really create a closure when the lexical is declared at the top level outside of any subroutine (I may be wrong, but it's at least a closure that doesn't create any problems...yet). So this works ok:
      use strict; use warnings; my $foo = 'foo'; bar(); $foo = 'bar'; bar(); sub bar { print "$foo\n"; }
      The problem comes when the script is run under Apache::Registry, because it turns the script into something like this:
      sub foo1234 { use strict; use warnings; my $foo = 'foo'; bar(); $foo = 'bar'; bar(); sub bar { print "$foo\n"; } } # Execute once foo1234(); # Execute twice foo1234(); OUTPUT: foo bar bar bar
      This gives you '$foo will not stay shared' warnings, and the result is that '$foo' does not change after the first execution of the subroutine that Apache::Registry wraps your script in. And mod_perl executes this subroutine over and over again (that's how Apache::Registry keeps your script persistent within mod_perl).