Description
When lexical subs (my sub
) that close over outer lexicals are used in subs that are recursive, weird things happen. It looks like Perl doesn't realize that the inner sub is a closure and has to be allocated at runtime (once per level of recursion). Instead Perl just reuses the same inner sub, overwriting its bindings.
Steps to Reproduce
#!/usr/bin/env perl use strict; use warnings; use feature 'lexical_subs'; sub outer { my ($x) = @_; my sub inner { my ($label) = @_; print "inner($label): \$x = $x at ", \$x, "\n"; } print "outer($x): \\&inner = ", \&inner, "\n"; inner "before"; outer($x - 1) if $x > 0; inner "after"; } print "Attempt 1:\n"; outer 2; print "\n", "Attempt 2:\n"; outer 2; __END__
Output:
Attempt 1:
outer(2): \&inner = CODE(0x55c73e8332b0)
inner(before): $x = 2 at SCALAR(0x55c73e87c180)
outer(1): \&inner = CODE(0x55c73e8332b0)
inner(before): $x = 1 at SCALAR(0x55c73e8121a0)
outer(0): \&inner = CODE(0x55c73e8332b0)
inner(before): $x = 0 at SCALAR(0x55c73e833370)
inner(after): $x = 0 at SCALAR(0x55c73e833370)
inner(after): $x = 0 at SCALAR(0x55c73e833370)
inner(after): $x = 0 at SCALAR(0x55c73e833370)
Attempt 2:
outer(2): \&inner = CODE(0x55c73e8332b0)
inner(before): $x = 2 at SCALAR(0x55c73e87c180)
outer(1): \&inner = CODE(0x55c73e833340)
inner(before): $x = 1 at SCALAR(0x55c73e8121a0)
outer(0): \&inner = CODE(0x55c73e833640)
inner(before): $x = 0 at SCALAR(0x55c73e833388)
inner(after): $x = 0 at SCALAR(0x55c73e833388)
inner(after): $x = 1 at SCALAR(0x55c73e8121a0)
inner(after): $x = 2 at SCALAR(0x55c73e87c180)
Expected behavior
"Attempt 1" is the broken case. Note in particular that all three levels of outer
recursion seem to share the same inner
sub (\&inner = CODE(0x55c73e8332b0)
) and that the inner(after)
calls at each level of outer
recursion see the same $x
variable (with value 0), namely the one from the innermost (outer(0)
) level of recursion.
"Attempt 2" is the expected behavior (I don't know why it behaves differently when called a second time). Here every level of outer
has a different inner
sub, and inner
at each level of recursion sees a different $x
variable, both before and after the recursive call to outer
.
This bug is reproducible in all perl versions I've tried: 5.39.6, 5.38.2, 5.38.0, 5.36.0, 5.34.1, 5.30.3, 5.26.1, 5.20.3.
(Thanks to vms14 from libera.chat #perl for finding this!)
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4