The reason I want to use anonymous subs instead of named ones is because I want to define these subs inside Mason subcomponents(http://www.masonbook.com/book/chapter-2.mhtml#TOC-ANCHOR-7), which don't behave well with named subs.
E.g. if I write code in that way:
my ($first, $second);
$first = sub {
my $val = shift;
print "val: $val";
$second->($val);
};
$second = sub {
my $val = shift;
if (0 < $val) {
$val = $val - 1;
$first->($val);
}
};
$first->(10);
Are there any hidden gotchas(e.g. memory leaks, etc.) in this approach?
As explained by @Schwern, memory for these subs won't be released by Perl, as there's a circular reference between them.
But more specifically, will the memory allocation grow linearly, as $val is increased, or it doesn't depend on invocation stack depth? Because I can put these subs in mason <%once> blocks, and in that case these subs will be initialized only once.
The only one I can think of is that the subroutines will never be deallocated, even if $first
and $second
go out of scope. $first
's code refers to $second
, $second
's code refers to $first
. This is a circular data structure, and Perl's memory allocation cannot deallocate that.
$ perl -wlE 'for (1..10_000) { my($first, $second); $first = sub {}; $second = sub {} } say "Done"; sleep 1000'
$ perl -wlE 'for (1..10_000) { my($first, $second); $first = sub { $second->() }; $second = sub { $first->() } } say "Done"; sleep 1000'
The first Perl process uses 1912K after the loop, the second uses 10320K. The first will not grow no matter how many CVs are created, the second will.
To get around this, you have to break the circle by undefining $first
or $second
. This third one calls undef $first
inside the loop, its memory does not grow.
$ perl -wlE 'for (1..100_000) { my($first, $second); $first = sub { $second->() }; $second = sub { $first->() }; undef $first; } say "Done"; sleep 1000'