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

Oh, Most Monkilicious Monks:

In preparing a reply to Making variables visible between calls. by ambs, I came across an odd bit of behavior. Someone else posted essentially the same idea first, so I never posted my reply. However, the problem that slowed me down is the subject of this post.
I have tested this with ActiveState Win32 Perl 5.6.1 and 5.8.2.

The intent was to add another little feature to the mix: a variable commonly accessible to all functions defined via create_f(). This variable could have its own get/set methods for global access as needed. The problem is that in the code below, the variable $common in the closure of the function create_f() does not have a defined value within the string eval statement in the function unless preceded by some kind of access to the variable. (Any of the access statements shown will do the trick.) Note that in the absence of any preceding access, the variable is in scope within the eval statement, just not defined!

I cannot see how this could be syntactically correct behavior. If it is, I would be very interested to know an explanation!

Many thanks for any insight my fellow monks may offer.

use warnings; use strict; BEGIN { # closure: data in scope only to create_f() function my $common = 'fooble'; sub create_f { my ($user_source, # required: string: user source code ) = @_; my $private = 'xpto'; # ??? makes $common variable defined in eval ??? # any of these statements do the trick. # except as noted, tested in both 5.6.1 and 5.8.2 # print "in create_f(): common: $common \n"; # $common .= ''; map defined, $common; # note: not tested with 5.6.1 my $coderef = eval qq{ sub { $user_source } }; return $coderef; # code reference undefined if eval failed } } # end closure: create_f() function # NOTE: single quotes on here-doc tag below: no interpolation. my $function = create_f(<<'USER_CODE'); my $param = shift; print "param: $param common: $common private: $private \n"; return join ';', $param, $common, $private; USER_CODE my $freturn = $function->('hi there'); print "function return: `$freturn' \n";
Output with preceding access to $common variable:
>perl t_create_f_PM.pl param: hi there common: fooble private: xpto function return: `hi there;fooble;xpto'
Output without preceding access to variable:
>perl t_create_f_PM.pl Use of uninitialized value in concatenation (.) or string at (eval 1) +line 2. param: hi there common: private: xpto Use of uninitialized value in join or string at (eval 1) line 3. function return: `hi there;;xpto'

Replies are listed 'Best First'.
Re: Non-definition of lexical referenced in string eval
by Tanktalus (Canon) on Dec 16, 2008 at 15:54 UTC

    I think you may be looking for Doubly-nested deeply bound variable is undefined, which is the same thing, but without eval STR. From a response by chromatic there, this may be fixed in perl 5.10. I say "may" because you're using an eval-string which may cause it to be different from the bug reported, but, still, it might work :-)

      ...this may be fixed in perl 5.10

      For the record, 5.10.0 in this case (without preceding access) warns 'Variable "$common" is not available at (eval 1) line 2.'.

        Thanks almut, I think you resolved two posts in one.
      Ah — Now some light begins to glimmer! Many thanks.
Re: Non-definition of lexical referenced in string eval
by cdarke (Prior) on Dec 16, 2008 at 15:07 UTC
    I raised this in my very first post 541345, and never really got a satisfactory explanation of the behaviour. However, there is (almost) always a better way to do it than eval.
      You know, I thought I remembered some sort of discussion of a similar topic somewhere, but I just couldn't reference it!

      The reply Re^3: eval a reference to a my hash by chromatic seems to provide some explanation, but I still can't understand why, if the lexical "[doesn't] really have [a name] anymore", the variable is still in scope and accessible by name, but just undefined.

        Lexical names get translated into indexed accesses into lexical pads at compile time. For a metaphor, imagine that the compiler keeps a hash translating $lexname to $lex_id. When a doubly-nested eval runs at runtime, the name doesn't really exist anymore.