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

I have a mainwindow with three buttons:
#!/usr/bin/perl -w + use Tk; use strict; my $mw = MainWindow->new; my $var=0; my $button_A = $mw->Button( -text => ' Button A', -command =>[\&rutine, $var, ]);# $button_A->pack; my $button_B = $mw->Button( -text => ' ++ ', -command => sub{$var++; print"\$var is $var!\n";}); $button_B->pack; my $button_C = $mw->Button( -text => ' -- ', -command => sub{$var--; print"\$var is $var!\n";}); $button_C->pack; MainLoop; sub rutine { my ($var)=@_; print "$var\n"; }
Button A prints the value of variable $var. Button '++' increments $var and Button '--' decrements $var. However if I first increment $var with '++' and then want to print its value with "Button A" the value of $var is 0 why is this? I guess I have missed something fundamental is it so? Thank you for your help.

Replies are listed 'Best First'.
Re: Fundamental tk-problem
by liverpole (Monsignor) on Nov 13, 2006 at 15:17 UTC
    Hi tamaguchi,

    It's because you're passing a copy of the variable to your rutine subroutine, rather than a reference to it.

    Try this instead:

    #!/usr/bin/perl -w + use Tk; use strict; + my $mw = MainWindow->new; + my $var=0; + my $button_A = $mw->Button( -text => ' Button A', -command =>[\&rutine, \$var, ]);# $button_A->pack; + my $button_B = $mw->Button( -text => ' ++ ', -command => sub{$var++; print "\$var is $var!\n";}); $button_B->pack; + my $button_C = $mw->Button( -text => ' -- ', -command => sub{$var--; print"\$var is $var!\n";}); $button_C->pack; + MainLoop; + + sub rutine { my ($pvar)=@_; + print "\$pvar => $$pvar\n"; + }

    Update:  To elaborate a bit...

    When you create the anonymous subroutine -command => sub{$var++;  print "\$var is $var!\n";}); for the "++" button (and the similar one for "--"), you were still in the same lexical scope of the original my $var=0; a few lines above, so it's not modifying the value of "$var" until it's called.

    But in your original code, [-command =>[\&rutine, $var, ]); is taking a "snapshot" of the value of "$var" and using that value instead of the current value.

    Another way to fix it would be to simply use an anonymous subroutine (and use your original rutine subroutine) which would correctly use the current value of "$var" when invoked:

    my $button_A = $mw->Button( -text => ' Button A', # -command =>[\&rutine, \$var, ]);# -command => sub{ rutine($var) }); $button_A->pack; # ... sub rutine { my ($var)=@_; + print "\$var => $var\n"; + }

    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
      Thank you very much for your reply Sir. I wish that I get as skilled as you some day.