in reply to Strange behavior of iteration while creating Perl/Tk widgets dynamically

Your problem can be demonstrated by following simple code:

my @subs; for(my $i=1;$i<=5;$i++){ push @subs, sub { print "i=$i\n"; }; } $subs[3]->();

Inside the sub, $i is evaluated at the time the sub is called in the context/scope of the for-loop which has now terminated, so $i=5+1=6, which is the expected behaviour.

A workaround would be to create a sub via eval which will force it to consider $i's value at the time of the eval. But I am not sure if this is an elegant solution:

my @subs; for(my $i=1;$i<=5;$i++){ push @subs, eval <<EOE; sub { print "i=$i\n"; }; EOE } $subs[3]->();

btw, once you sort this out, you should start using arrays instead of ${"xx$i"}!

Update: another solution would be to introduce another variable local to the loop scope and use that:

my @subs; for(my $i=1;$i<=5;$i++){ my $j = $i; push @subs, sub { print "i=$i, j=$j\n"; }; } $subs[3]->();

Question: what's the difference between $i and $j, don't they both have the same scope?

bw, bliako

Replies are listed 'Best First'.
Re^2: Strange behavior of iteration while creating Perl/Tk widgets dynamically
by BillKSmith (Monsignor) on Oct 29, 2021 at 14:34 UTC
    The perl foreach (or its alias for) loop does not have this problem.
    my @subs; #for(my $i=1;$i<=5;$i++){ for my $i (1..5) { push @subs, sub { print "i=$i\n"; }; } $subs[3]->();

    OUTPUT:

    i=4
    Bill

      And this code confirms your finding:

      my @subs; for(my $i=1;$i<=2;$i++){ print \$i."\n" } print "----\n"; for my $i (1..2) { print \$i."\n" }

      OUTPUT:

      SCALAR(0x55a429b66a28) SCALAR(0x55a429b66a28) ---- SCALAR(0x56399466d4d8) SCALAR(0x5639946924a0)

      Which made me try this:

      my @subs; my $i; for($i=1;$i<=5;$i++){ push @subs, sub { print "i=$i\n"; }; } $i = 100; $subs[3]->();

      It prints i=100

      bw, bliako