jutky jutky - 1 month ago 13
Perl Question

Perl variables scoping

I wanted to remove duplicate values from an array with this approach. The duplicates removal have to be executed inside a loop.
Here is a minimal example that demonstrates the problem that I encountered:

use strict;

for (0..1){
my %seen;
sub testUnique{
return !$seen{shift}++;
}

my $res = testUnique(1);

if($res){
print "unique\n";
}else{
print "non-unique\n";
}
}


I define the
%seen
hash inside a loop, so I would expect it to be defined only during a single iteration of the loop.
The result of the above code is however:

unique
non-unique


With some debug prints, I found out that the value of
%seen
is preserved from one iteration to another.

I tried a trivial

for (0..1){
my %seen;
$seen{1}++;
print "$seen{1}\n";
}


And this one worked as expected. It printed:

1
1


So, I guess the problem is with inner function
testUnique
.
Can somebody explain me what is going on here?

Answer

Your testUnique sub closes over the first instance of %seen. Even though it is inside the for loop, the subroutine does not get compiled repeatedly.

Your code is compiled once, including the part that says initialize a lexically scoped variable %hash right at the top of the for loop.

The following will produce the output you want, but I am not sure I see are going down this path:

#!/usr/bin/env perl

use warnings;
use strict;

for (0..1){
    my %seen;
    my $tester = sub {
        return !$seen{shift}++;
    };

    print $tester->(1) ? "unique\n" : "not unique\n";
}