in reply to Scope problem in closures with an eval statement

The problem is not that $k is garbage collected, but that it's not included in the closure. Actually your first sub doesn't return a closure at all, because no variables from the outer scope are enclosed (at compile time) in the anonymous sub at all.

If you can in your case, you could use the non-string form of eval:

sub emphasizePrint { my $k = "!!\n"; return sub { my ($str) = @_; eval { print "$str$k" }; print STDERR "Error: $@" if ($@); } }

If that isn't applicable in your case I know no other way around than mentioning the variables in the closure once.

Replies are listed 'Best First'.
Re^2: Scope problem in closures with an eval statement
by ysth (Canon) on Apr 15, 2008 at 06:57 UTC
    No, the problem is that $k is not available (slightly different than garbage collected). It is included in the closure, as this demonstrates:
    use strict; use warnings; $::clos = $::clos = "global"; sub foo { my $clos = shift; my $sub = shift; &$sub() if $sub; return sub { eval 'print "$clos\n"' } } foo("baz", foo("bar"));
    The first (inside) call to foo returns a closure on foo's $clos. The second call to foo calls the closure, which does get the closed-over $clos. But there is a problem: entering foo the second time reuses the same lexical $clos, since perl isn't aware that the first call will be referring to it, so as an optimization doesn't bother allocating a new lexical.

    Note that in 5.10.0, the OP's problem code gives a warning:

    Variable "$k" is not available at (eval 1) line 1.