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

Copied from one of the Perl Discords:

By user "timka7060":

Who can figure this out. I narrowed down my issue in some other code to this simple use case:
# Can print $v only once!!! # Second call returns undef. # Some coderef optimization??? # Lexical variable goes undef on second call. # sub { my $v = 111; eval q( eval 'print $v, "\n"'; # 111 eval 'print $v, "\n"'; # undef ); }->();

User "tyrrminal" replies with:

If you enable warnings, you see a line Variable "$v" is not available at (eval 3) line 1. Googling that led me to a stack overflow response which seems to relate to your case (2nd answer, starting with See perldiag)

timka7060's reaction:

So why does the first eval output 111?
(I'd figure either both lines should be 111 or both undef.)
Btw, prior to 5.10, both lines would output 111: https://perlbanjo.com/b28dce8db2
This is a simple fix, but only for a single variable: https://perlbanjo.com/13dbb8d48d

My observation:

sub { my $v = 111; eval q( eval 'print $v, "A\n"'; eval 'print $v, "B\n"'; print $v, "C\n"; ); }->();
Now, none of either A or B sees $v, but C (obviously) does.

What's going on here?

map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

Replies are listed 'Best First'.
Re: Lexical variable not available
by dave_the_m (Monsignor) on Mar 22, 2024 at 14:13 UTC
    I've made a PR with a fix

    Dave.

Re: Lexical variable not available
by dave_the_m (Monsignor) on Mar 18, 2024 at 23:54 UTC
    Smells like a bug to me.

    Dave.

Re: Lexical variable not available
by ikegami (Patriarch) on Mar 19, 2024 at 19:45 UTC

    Only variables referenced by a sub are captured by a sub.

    use strict; use warnings; use feature qw( say ); sub f { my $x = shift; return sub { $x }; } sub g { my $y = shift; return sub { eval '$y' }; } sub h { my $z = shift; return sub { $z if 0; eval '$z' }; } say f( 4 )->() // "[undef]"; say f( 5 )->() // "[undef]"; say "--"; say g( 6 )->() // "[undef]"; say g( 7 )->() // "[undef]"; say "--"; say h( 8 )->() // "[undef]"; say h( 9 )->() // "[undef]";
    4 5 -- Variable "$y" is not available at (eval 1) line 1. [undef] Variable "$y" is not available at (eval 2) line 1. [undef] -- 8 9

    This is an optimization as capturing everything every time would have drawbacks.

    I can't explain the behaviour you are seeing, but the bug you are encountering is surely related to this optimization.

    In any case, adding the following to your outer eval works around the issue:

    my $v = $v;

      but the bug you are encountering is surely related to this optimization.

      It could be. But the more I think of this, the more I think it might not necessarily be the case.

      Well, at least the reader now knows the common cause of this error.

Re: Lexical variable not available
by LanX (Saint) on Mar 18, 2024 at 21:34 UTC
    my (wild) guess is compile-time vs run-time confusion with lex-pads.

    Each sub (and block) has a so called lex-pad where all it's own and closed-over lexicals are listed¹. That's all settled at compile-time.

    These evals are kind of accessing closed-over vars but at run-time.

    But I doubt anyone thought about testing this with nested evals.

    I suppose evals have a lex-pad too, but when exactly is it intialised?

    TL;DR

    I think different evals are accessing different scopes because of race conditions. Introducing {BLOCKS} and anonymous subs into the evaled code might fix this.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery

    ¹) compare PadWalker

Re: Lexical variable not available
by InfiniteSilence (Curate) on Mar 20, 2024 at 01:16 UTC

    I would just be more explicit as to where these variables are stored if I wanted to make certain there were available in evals:

    #!/usr/bin/perl -w sub { package Romania; our $v = 111; eval q( eval 'print $v, "\n"'; # 111 eval 'print $v, "\n"'; # still 111 of course ); }->(); print qq~----\n~; print qq!$Romania::v\n!;

    Prints..

    111 111 ---- 111

    Celebrate Intellectual Diversity

Re: Lexical variable not available
by Danny (Chaplain) on Mar 18, 2024 at 21:54 UTC
    This works fine, so it seems to be how the q() is compiled.
    sub { my $v = 111; eval { eval 'print $v, " x\n"'; eval 'print $v, " y\n"'; print $v, " z\n"; }; }->();
      The main difference should be when the block eval versus the string eval is compiled, not how.

      map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      Two very different kinds of eval

      Without the q{} you are essentially only doing block-eval which is Perl's version of a try-catch

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery