Is it safe to recursively call one anonymous subuser from another?

The reason I want to use anonymous subtitles instead of the ones I have is because I want to define these subsets within the Mason subcomponents ( http://www.masonbook.com/book/chapter-2.mhtml#TOC-ANCHOR-7 ) that do not behave well with named subs.

eg. if I write code this 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 hidden gotchas in this approach (e.g. memory leaks, etc.)?

As explained by @Schwern, the memory for these subscriptions will not be released by Perl, as there is a circular link.

But more specifically, will the memory allocation grow linearly, since $ val increases or does not depend on the depth of the call stack? Because I can put these submarines in mason <% once> blocks, in which case these subs will be initialized only once.

+5
source share
2 answers

The only thing I can think of is that routines will never be freed even if $first and $second go out of scope. $first code refers to $second , $second code refers to $first . This is a circular data structure, and memory allocation in Perl cannot free it.

 $ 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 be.

To get around this, you must break the circle by specifying $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' 
+4
source

It would be nice:

 sub first { my $val = shift; print "val: $val"; second($val); } sub second { my $val = shift; if (0 < $val) { $val = $val - 1; first($val); } } first(10); 

The only caveat is that you need to declare subtitles if they have a prototype, or if you want to omit parsers around your arguments.

 sub first($); sub second($); sub first($) { my $val = shift; print "val: $val"; second $val; } sub second($) { my $val = shift; if (0 < $val) { $val = $val - 1; first $val; } } first 10; 

Your version, on the other hand, has a memory leak. The first auxiliary element captures the link to the second sub, which captures the link to the first unit.

 $ perl -e' sub DESTROY { print "Destroyed\n" } { my ($first, $second); $first = sub { $second }; $second = sub { $first }; bless($first); } print("Subs should have been destroyed by now\n"); ' Subs should have been destroyed by now Destroyed 

The decision depends on why you decided to use anon subs in the first place.

+2
source

Source: https://habr.com/ru/post/1232564/


All Articles