Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Confused about 'Name "main::whenfound" used only once:'

by Maze (Sexton)
on Aug 09, 2006 at 12:34 UTC ( [id://566390]=perlquestion: print w/replies, xml ) Need Help??

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

Perl seems to be an amazingly succint way of writing programs, but I seem to be having a nightmare debugging this simple script!
#!/usr/bin/perl #testargscan.pl - a script for testing use warnings; sub argscan{ if ($#ARGV == 1) {return (0)} else { my @subarg = (qw($_[0] $_[1] $_[2])); my $argcount = 0; my $found; my $notfound; my @whenfound; while ($argcount <= $#ARGV) { if ($subarg[0] = undef) { $argcount = $#ARGV; return $argcount } if ($ARGV[$argcount] == $subarg[0]){ $found++; $whenfound[$argcount] = 1; } else { $notfound++; $whenfound[$argcount] = 0; #goto (proper) } unless ($argcount == $#ARGV) { $argcount++ } } } if ($subarg[1] eq 'foundcount') { unless ($found == undef) { return $found} else {return 0} } elsif ($subarg[1] eq 'argcount'){ unless ($argcount == undef) { return $argcount} else {return 0} } elsif ($subarg[1] eq 'notfoundcount') { unless ($notfound == undef) { return $notfound} else {return 0} } elsif ($subarg[1] eq 'hunt') { unless ($found == undef) { return $whenfound[$subarg[2]]} else {return 0} } else {return 0}; } $argnumber = argscan(undef); $carnumber = argscan(qw (car foundcount)); $notcarnumber = argscan(qw(car notfoundcount)); $bunnynumber = argscan(qw(bunny foundcount)); print "there are $argnumber arguments \n there are $carnumber cars there are $bunnynumber bunnies $notcarnumber args are not cars \n ";
it's probably a pretty shoddy piece of code, I keep on getting very odd error messages such as:

"Name "main::whenfound" used only once: possible typo at testargscan.pl line 54."

when that isn't true, and sometimes the perl interpreter just freezes
If someone will tell me what i'm missing I can go though the process of feeling stupid for not realising it and then learning from my mistake
PS: It can work, but all the final values will be 0

2006-08-09 Retitled by Corion, as per Monastery guidelines
Original title: 'Confused'

Replies are listed 'Best First'.
Re: Confused about 'Name "main::whenfound" used only once:'
by Corion (Patriarch) on Aug 09, 2006 at 12:39 UTC

    But Perl is right when it issues that warning! If you would use strict;, Perl would even have caught your underlying programming error. The array @whenfound is declared only in your sub argscan { ... }. Perl sees you use another array @whenfound in your main program, and warns you that you only ever use this array once, in line 54, which is correct.

    You should read about the strict pragma and add the line use strict; before the line use warnings; in your program. Then you should go through your script and fix all the places where a variable is used but has not yet been declared, by declaring that variable either through use vars '$variable'; or by my $variable;, depending on whether you want that variable to be a global variable or a local variable.

    After you've such declared the scope of all your variables, you will in the course also have found the logic errors in your program that were caused by using variables before they even got assigned a value.

Re: Confused about 'Name "main::whenfound" used only once:'
by cdarke (Prior) on Aug 09, 2006 at 13:42 UTC
    Just an observation about your code. $#ARGV is the highest index number in the array @ARGV. If you need to know how many elements in an array, then use it in scalar context, for example:
    $argc = @ARGV; if ( @ARGV == 2) {

    etc.
Re: Confused about 'Name "main::whenfound" used only once:'
by merlyn (Sage) on Aug 09, 2006 at 15:27 UTC
    I stopped reading when I hit here: qw($_[0] $_[1] $_[2]).

    Do you want a list that consists of three elements, the first of which is literally a dollar, underscore, left bracket, zero, right bracket?

    Your code appears to be random snippets cut-n-pasted into the same file, without any real understanding of what each piece does. Perhaps you should start with a good tutorial book (I can recommend a couple {grin}), and work through the exercises slowly and carefully.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: Confused
by blazar (Canon) on Aug 09, 2006 at 14:02 UTC
    use warnings; sub argscan{ if ($#ARGV == 1) {return (0)}

    All in all, what a mess! First, I'm confused by your indenting style. Then you miss the important

    use strict;

    line. And last (for these three lines), you write a sub to work on the global @ARGV variable. Subs are for having args passed into them. It may not that bad to have it like this, instead, but as a general rule it's not that nice a programming technique. And subs are typically for factorizing code that is to be applied in different situations, but if that's for cmd line arguments scanning, that code may well not be factorized away.

    As far as the rest goes, I have the overall impression that you're doing far too much work, but I don't feel like trying to guess your task. May you describe in words what your script is supposed to do? We may offer a hopefully simpler alternative as a starting point to you...

Re: Confused about 'Name "main::whenfound" used only once:'
by gellyfish (Monsignor) on Aug 09, 2006 at 15:31 UTC

    I think you will find that it is the use of @whenfound in the:

    unless ($found == undef) { return $whenfound[$subarg[2]]} else {return 0}
    The problem is that you have declared my @whenfound in a different lexical scope to the one that you are using it there in - it's not a problem early in the code as those uses are the same scope as the declaration. Because you are not using strict the out-of-scope reference to @whenfound is assumed to be to the package variable @main::whenfound to which this is the only reference and hence the warning.

    The bottom line, as everyone else has pointed out, is that you should have used strict

    /J\

Re: Confused about 'Name "main::whenfound" used only once:'
by Moron (Curate) on Aug 09, 2006 at 14:39 UTC
    I must admit that whenever I see that error message my brain translates it into something like the following English:

    "Name ____ is used uselessly, i.e. before it is assigned to anything in _____.pl at line ____"

    (Update: oops that isn't really English -- it's just better "Errormessagese")

    Although a typo is the most likely cause, this should in general widen to include such things as "You might have forgotten to initialise it or use it in an assignment that gives it a defined value"

    One day maybe they'll teach the Errormessagese language in schools ;)

    More update: I also agree with others who advise "use strict" - it might produce even more errors but it's always better to investigate and fix than to hide such errors and remain ignorant of what they are for.

    -M

    Free your mind

Re: Confused about 'Name "main::whenfound" used only once:'
by fishbot_v2 (Chaplain) on Aug 09, 2006 at 20:38 UTC

    Your problem has been identified, and a number of other issues have been pointed out. This one hasn't been mentioned, but caught my eye:

    unless ($found == undef) { ...

    That's not doing what you probably think it is. undef in a numeric context like that is 0. So, if $found is... wait, where is $found being set? Actually, I have no idea what is happening there.

    The point was that you should test definedness with defined():

    if ( defined( $found )) {...}

    Thanks to a series of coersions, your code is functionally equivalent to:

    if ( $found ) { ... }
Re: Confused about 'Name "main::whenfound" used only once:'
by eff_i_g (Curate) on Aug 09, 2006 at 14:02 UTC
    In instances where you may not have typos—those exist?—, etc., you can disable the warning like so:
    { no warnings 'once'; # ... }
    For now I'd follow the advice of Corion.
Reply to replies and update
by Maze (Sexton) on Aug 09, 2006 at 22:48 UTC

    hm - right, i fix up the indentations
    use the appropriate things for finding values
    put the declarations in the correct 'scope'
    use strict
    and er... stop the braindeaded use of qw...

    and so with various other edits, this is what i've come up with

    #!/usr/bin/perl use strict; use warnings; sub argscan{ my @subarg = ($_[0],$_[1],$_[2]); my $argcount; my $found; my $notfound; my @whenfound; if (@ARGV == 1) { return 0; } elsif ($subarg[0] = undef) { $argcount = @ARGV; return $argcount; } else { while ($argcount <= @ARGV) { if ($ARGV[$argcount] == $subarg[0]){ $found++; $whenfound[$argcount] = 1; } else { $notfound++; $whenfound[$argcount] = 0; } $argcount++; } if ($subarg[1] eq "foundcount") { if (defined($found)) { return $found } } elsif ($subarg[1] eq "notfoundcount") { if (defined($notfound)) { return $notfound } } elsif ($subarg[1] eq "huntfor") { if (defined($found)) { return $whenfound[$subarg[2]] } } else {return 0 } } } my $argnumber = argscan(); my $carnumber = argscan(qw(car foundcount)); my $notcarnumber = argscan(qw(car notfoundcount)); my $bunnynumber = argscan(qw(bunny foundcount)); print "there are $argnumber arguments \n there are $carnumber cars there are $bunnynumber bunnies $notcarnumber args are not cars \n ";

    which executes and produces the output:
    there are 0 arguments
    
            there are 0 cars
            there are 0 bunnies
            0 args are not cars
    
    when I execute it with any given argument

    and gives this output when I execute it with any arguments:
    Use of uninitialized value in numeric le (<=) at testargscan.pl line 18.
    Use of uninitialized value in array element at testargscan.pl line 19.
    Use of uninitialized value in numeric eq (==) at testargscan.pl line 19.
    Use of uninitialized value in numeric eq (==) at testargscan.pl line 19.
    Use of uninitialized value in array element at testargscan.pl line 21.
    Use of uninitialized value in string eq at testargscan.pl line 29.
    Use of uninitialized value in string eq at testargscan.pl line 29.
    Use of uninitialized value in string eq at testargscan.pl line 29.
    Use of uninitialized value in numeric le (<=) at testargscan.pl line 18.
    Use of uninitialized value in array element at testargscan.pl line 19.
    Use of uninitialized value in numeric eq (==) at testargscan.pl line 19.
    Use of uninitialized value in numeric eq (==) at testargscan.pl line 19.
    Use of uninitialized value in array element at testargscan.pl line 21.
    Use of uninitialized value in numeric le (<=) at testargscan.pl line 18.
    Use of uninitialized value in array element at testargscan.pl line 19.
    Use of uninitialized value in numeric eq (==) at testargscan.pl line 19.
    Use of uninitialized value in numeric eq (==) at testargscan.pl line 19.
    Use of uninitialized value in array element at testargscan.pl line 21.
    Use of uninitialized value in numeric le (<=) at testargscan.pl line 18.
    Use of uninitialized value in array element at testargscan.pl line 19.
    Use of uninitialized value in numeric eq (==) at testargscan.pl line 19.
    Use of uninitialized value in numeric eq (==) at testargscan.pl line 19.
    Use of uninitialized value in array element at testargscan.pl line 21.
    there are 0 arguments
    
            there are 1 cars
            there are 1 bunnies
             args are not cars
    
    which isn't the bahaviour i'm looking for

    what I am looking for is a simple test of a subroutine, which I'm trying to use in a larger program for XML handling, cycles through the argument array looking for the values specified when I call it (in this case - cars and bunnies, just because I could) and returning what I ask for.

    so should be pretty easy, except I must be doing something fundamentally wrong
    thanks for peoples help, and as for tutorials, i've only had a breif look at llama book and read some source code, so i'm not surprised I'm making careless mistakes
    i'll get back to it

      It appears you are trying to make one subroutine do the work of several, and distinguishing which by the number and content of your "subargs" (which I will call "parameters" to your sub, to distinguish them from the command line arguments in @ARGV). This one sub does five different things:

      • With no parameters passed, counts the number of arguments passed on the command line;
      • Otherwise, takes its first parameter and compares it against each command line argument, keeping a count of the number of matches and nonmatches;
      • If the second parameter matches a given string, returns the count of matches determined above;
      • If the second parameter matches a different string, returns the count of nonmatches given above; and
      • If the second parameter matches yet something else, tries to do something I can't figure out. Since this is never tested by the test cases given, I'm going to ignore this case entirely and leave it to you and to the other monks.

      I would structure this monster as a number of different subroutines. Basically, get rid of the second parameter to your catch-all sub; then write one subroutine to do each of the five tasks above, using the sub's name to convey the same information. The first sub, however, is probably better written right into your mainline code, as it operates on the global @ARGV -- for now. The second sub would be called in turn by the following two or three.

      Furthermore, I wouldn't necessarily rely on the fact that the list you are searching for resides in @ARGV, for the simple reason that a real program will very likely accept its data from a file or other source rather than as discrete command-line arguments. Copy the arguments into a normal array and pass a reference to this array to the task subroutines above. If you have no idea what I mean by references at the moment, click or run perldoc perlreftut.

      Oh, and your uninitialized variables problems will pretty much Go Away if you do two things:

      • set all your "my" variables to a value (preferably 0 or "") when you declare them, and
      • instead of testing for defined (which you haven't quite got the hang of yet), just test for nonzero/non-null: if ($variable) instead of if (defined $variable).

      You're getting there, just not quite there yet.

      Your line 12:

      elsif ($subarg[0] = undef) {

      Always evaluates to true. You probably meant:
      elsif ($subarg[0] == undef) {

      s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}

        Good catch, but $subarg[0] = undef always evaluates to *false* (not true), and $subarg[0] == undef is also wrong.

        elsif (not defined $subarg[0]) {

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://566390]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2024-04-25 15:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found