Dear Monks,
I have a little problem:
use warnings;
use 5.010;
for my $num (1 .. 5) {
my $a = $num;
{say "in block: $a"};
sub test {
say "in function: $a";
}
test()
}
--output:--
in block: 1
in function: 1
in block: 2
in function: 1
in block: 3
in function: 1
in block: 4
in function: 1
in block: 5
in function: 1
I assume a closure is what's causing the sub to print the same output over and over again. However, the only thing I can find in the docs about closures is in relation to anonymous subs, yet this program is using a named sub.
Is the closure problem an artifact of perl trying to be efficient and not redefining the function every time through the loop? Why don't the docs mention that a named sub can create a closure? Could someone give a blow by blow description of what's happening?
That closure problem sprang up when sorting a hash inside a loop. The following program sorts two hashes by their values, which are integers. The hashes are stored in an array, so a for loop is used to step through the array. Then one hash is sorted each time through the loop, and its results are immediately displayed:
use strict;
use warnings;
use 5.010;
my %h1 = (
'a' => 5,
'b' => 8,
'c' => 1
);
my %h2 = (
'a' => 200,
'b' => 150,
'c' => 100
);
my @AoH = (\%h1, \%h2);
for my $href (@AoH) {
my %hash = %$href;
my @sorted_keys = sort by_val keys %hash;
sub by_val {
$hash{$a} <=> $hash{$b}
};
for my $key (@sorted_keys) {
say "$key = $hash{$key}";
}
say "=" x 20;
}
--output:--
c = 1
a = 5
b = 8 #ok, the first hash is sorted perfectly.
====================
c = 100
a = 200
b = 150 #but what happened here?
====================
The problem can be cured by using a block with sort instead of defining a sub. This example shows that you should not be indifferent to using a block v. defining a sub when using sort().
edit: I also wanted to ask about this variation:
use strict;
use warnings;
use 5.010;
for my $num (1 .. 5) {
say "start of for loop: $num";
{say "in block: $num"};
sub test {
say "in function: $num";
}
test()
}
--output:--
start of for loop: 1
in block: 1
Use of uninitialized value $num in concatenation (.) or string at 3per
+l.pl line 11.
in function:
start of for loop: 2
in block: 2
Use of uninitialized value $num in concatenation (.) or string at 3per
+l.pl line 11.
in function:
..
..
In that variation, the sub can't see the my variable $num. Why?
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.