I have this application that I'm working on in Tk. Originally, I made all of the widgets globals so that I could do a  Tk::Exists($widget) on them. The reason for this was to ensure that I'm not recreating windows when the window already exists (duh, right?). Another thing that kind of stings is that most of the variables (objects, if you will) are used once, since they're containers for objects. Of course, warnings complains that "The variable is used only once." For a while, I just turned warnings off, but I think that's kind of silly.

In my eyes, to write good code, it should work under warnings and strict. In this case, however, I don't see any real way to get this code to do so. So, I'm wondering... Am I stressing strict and warnings to much, or is there some justification in my paranoia? Or, is it just that Tk doesn't really lend itself to strict and warnings for larger applications?

Theodore Charles III
Network Administrator
Los Angeles Senior High
4650 W. Olympic Blvd.
Los Angeles, CA 90019
323-937-3210 ext. 224
email->secon_kun@hotmail.com

Replies are listed 'Best First'.
Re: -w, strict, and Tk...
by {NULE} (Hermit) on Mar 20, 2002 at 00:52 UTC
    Hi Necos,

    Just a quick suggestion (must run off). What I frequently do with Tk apps (and I write lots of them) is to create an anonymous hash to hold all the widgets that I might need to address elsewhere.. Then I can pass that hash around and avoid globals. For example (psuedo code):

    my $w; $w->{main} = MainWindow->new; $w->{other_widgets} = $w->{main}->Label->.... # and then later... &subroutine($w); sub subroutine { my $w = shift; # Do stuff with $w here now like normal $w->{main}->configure( -title => "new title" ); }
    My personal rule is that if I get the variable used only once warning then I've done something wrong with my design and implementation and I should rework my solution.

    Update: demerphq makes a good point. To add to what is said there, I'd like to comment that there are lots of ways to reference a variable without context;

    1 if $a; # for example
    Another thing that I've done in the past when stuck with these kinds of warnings is to create a special subroutine just to reference them (assuming their global status):
    sub unused { warn "sub unused was used!!!\n"; return; 1 if $a; 1 if $b; }
    But I really feel that if you are in this situation you may wish to think carefully if there is a better way to accomplish what you are trying to do.

    Again, good luck - {NULE} (/Update).

    Final Update: Here is sample code that accomplishes what Necos wanted.

    #! /usr/bin/perl -w use strict; use Tk; use Tk::Toplevel; ################ # Main Routine # ################ my $w; $w->{main} = MainWindow->new(-title => 'Tk Hash'); $w->{main}->Button(-text => "Click me to open a new toplevel", -comman +d => [ \&new_tl, $w ])->pack; $w->{main}->Button(-text => "Click me to test for other button", -comm +and => [ \&test_tl, $w ])->pack; MainLoop; exit; ############### # Subroutines # ############### sub new_tl { my $w = shift; if ( not Tk::Exists $w->{toplevel} ) { $w->{toplevel} = $w->{main}->Toplevel( -takefocus => 1, -title + => 'Top Level' ); $w->{testbutton} = $w->{toplevel}->Button(-text => 'Null butto +n'); } else { $w->{toplevel}->deiconify(); $w->{toplevel}->raise(); $w->{toplevel}->focusForce(); } } sub test_tl { my $w = shift; if ( Tk::Exists $w->{testbutton} ) { print "testbutton exists\n"; } else { print "testbutton does not exist\n"; } }

    {NULE}
    --
    http://www.nule.org

Re: -w, strict, and Tk...
by rjray (Chaplain) on Mar 20, 2002 at 00:13 UTC

    I don't feel that strict can be stressed too much, but I do often see production code have the -w removed. Running with warnings enabled is good and helpful for development and testing, but the warnings are rarely helpful to the end-user, unless your user-base is also Perl-savvy.

    As for the "used only once" cases, that's hard to address without some code in front of me. I've written several applications with Tk, and in all the cases I can remember I had to use an object value more than once, even if all I did was use it to call pack after creation. If you are crafting your constructor calls such that it threads through from new --> pack in one (long, complex) statement, then maybe you don't need to be assigning the value to a variable? Why not just:

    <code> my $MW = Tk::MainWindow->new();

    $MW->button(-text => 'Quit', -command => sub { exit })->pack; <code>

    --rjray

      As per request, I've put the code up on my scratchpad. Basically, the only reason I need to keep a few of the named variables is so I can pull values from them (for example, I pull data from the Entry, and Listbox widgets). There might be a flaw in my design. If so, please point it out. I'm always looking for more tricks to better my Perl skills (and general programming skills for that matter).

      Theodore Charles III
      Network Administrator
      Los Angeles Senior High
      4650 W. Olympic Blvd.
      Los Angeles, CA 90019
      323-937-3210 ext. 224
      email->secon_kun@hotmail.com
Re: -w, strict, and Tk...
by demerphq (Chancellor) on Mar 20, 2002 at 12:31 UTC
    Of course, warnings complains that "The variable is used only once."

    This error pops up occasionally, usually for the right reason but occasionally, (such as where you declare a variable in your script but only acess the variable from within an eval), quite incorrectly.

    The solution is usually simple:

    use warnings; use strict; our $x; eval (' $x=1; print $x; '); #Generates a warning that $x is only used once.. Incorrectly. # {my $work_around=$x} # Uncomment to make the error go away.
    By adding the anonymous block with the (useless but for its side effect) lexical declaration and assignment of $x, the compiler has now seen the variable twice and the warning goes away, but with little cost or impact on your script. (In fact it wouldnt suprise me in the least if the compiler optimizes it away, _after_ the lexical analysis phase)

    If you had to make a bunch of these disappear then maybe

    { my @work_around=($x,$y,$z); }
    Would be the neatest way to resolve them all in one workaround.

    Yves / DeMerphq
    --
    This space for rent.

      Am I the only one who finds it a bit odd that you can remove a warning for a variable that is only used once by creating another variable that is... only used once???

      Why doesn't $work_around generate the same error it was introduced to stop?

      --
      my $chainsaw = 'Perl';

        Because it's lexical? The "only used once" warning only pops up for globals, I think.
        --
        Mike