PatGro has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,

It is my first post here. I have trouble understanding the difference between both version of my code. I am using tk for my gui. I am building an array of controls within a loop and, when I use the for loop construct, the code isn't working as expected.

my @tx_grid_frame; my @outputEnaLpbkBut; for (my $i = 0; $i < $self->{NUM_OF_LANE_MAX}; ++$i){ $tx_grid_frame[$i+1][1] = $quick_tx_right_frm->Frame(-relief=>'gro +ove', -bd=>1)->grid(-row => $i+1, -column => 1, -columnspan => 1, -r +owspan => 1, -sticky => 'nsew'); #Output enable when loopback $outputEnaLpbkBut[$i] = $self->{W}->Add_Chk($tx_grid_frame[$i+1][ +1], '', 'top'); $outputEnaLpbkBut[$i] -> configure(-variable=> \${$self->{OUTPUT_E +NA_LPBK}}[$i], -command => sub{ print "Test $i \n"; }); }
When this code execute, it always print  Test 10 If I change only the for loop for foreach my $i (0..$self->{NUM_OF_LANE_MAX}-1) { then the ID of the checkbox clicked is print, i.e. if I click on the 4th checkbox, I get  Test 4 As far as I understand, there should not be any differences between the two constructs. In my case, I don't understand the difference between the two codes that makes them behave differently.
Thank you for your insights,
P.

Replies are listed 'Best First'.
Re: Problem understanding why for loop won't work when foreach is working
by BrowserUk (Patriarch) on Aug 13, 2013 at 14:56 UTC

    If you do not know what a closure is, the following explanation probably won't help much.

    1. With the C-style for loop, the subroutine sub{ print "Test $i \n"; } is closing over the variable $i.

      That is, the value of the variable within the string is not interpolated until the subroutine is run, and by the time it is run, $i retains the last value it had when the loop completed -- Ie. 10 -- for all instances of the subroutine.

    2. With the foreach-style for loop; the subroutines are closing over aliases to the values produced by the range operator in the for loop.

      Thus each instance of the subroutine is closing over an alias to a different constant value, 1 .. 10.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Problem understanding why for loop won't work when foreach is working
by choroba (Cardinal) on Aug 13, 2013 at 14:57 UTC
    There is a subtle but important difference. You are using $i in the callback, which is a variable. In the C-style loop, you are creating a closure, and the variable does not disappear when the for loop ends: it is kept in the sub to be printed later. In the foreach case, though, $i is aliased to the elements you are iterating over. $i in this case is not a normal variable, it is an alias of the actual number. Try adding \$i into your test print to see the difference.
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Problem understanding why for loop won't work when foreach is working
by PatGro (Novice) on Aug 13, 2013 at 15:06 UTC
    Thank you both of you! I'll read more on closure later today but it makes sense when I tried to print \$i instead of $i.