I have just encountered the following strangeness:
A subroutine appears to 'remember' a
my variable
from it's previous invocation:
# A 'wannabe' foreach, which: # - takes a CODE ref as an optional first argument # - applies it to the rest of the args # - If no CODE ref was passed, then it uses a closure of its # own that simply shoves all the args into an accumulator list # which it just dumps to STDERR sub wannabe_foreach { my $func = shift if ref $_[0] eq 'CODE'; # optional code-ref # Funkiness: $func has a value if: # (a) the user gave it one; # (User thinks closures are funky) # (b) it mysteriously has a value. # (many people would call that 'funky') warn "my func is funky!\n" if $func; my @list = @_; my @accumulator = (); $func = sub { push @accumulator, shift } unless $func; $func->($_) for @list; warn join ",", @accumulator if @accumulator; } wannabe_foreach(1..3); # Works. Warns: '1,2,3 at foo.pl line ...' wannabe_foreach(1..4); # Gets funky. # Still funky, but at least the passed code ref is invoked. # wannabe_foreach(sub { print shift }, 1..7); print "\n"; # Plain funky again. # wannabe_foreach(1..7);
A cursory debugging shows that the line
Gets funny - $func retains a reference to the closure created in the previous invocation. Looks like the compiler is too eager to optimize the closure instances?my $func = shift if ref $_[0] eq 'CODE'; # optional code-ref
Well whatever the reason is, the fix was simply:
#my $func = shift if ref $_[0] eq 'CODE'; my $func = ref $_[0] eq 'CODE' ? shift() : undef;
So - I suspect some glaring 'overlooking the obvious' mistake on my part, but not having found a reason that I understand yet, I thought I'd ask you all.
In reply to Unforgettable Closures? by faiz
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |