Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Warning gets the line number wrong?

by Cap'n Steve (Friar)
on Apr 30, 2007 at 08:23 UTC ( #612715=perlquestion: print w/replies, xml ) Need Help??
Cap'n Steve has asked for the wisdom of the Perl Monks concerning the following question:

My script generates this warning: "Use of uninitialized value in numeric le (<=) at line 416."

The problem is that line 416 is just checking for a matching regular expression. The script is kind of big, but here's lines 406-425:
for (my $i = 0; $i <= $#_; $i++) { next unless $_[$i] =~ /^(.+?)\.(zip|t?gz|tar|bz2?|tbz)$/i or $_[$i] =~ /$config_regexp/i or $_[$i] =~ /banner\d?\.(jpe?g|gif|png)$/i or $_[$i] =~ /^template\.html?$/i; my($volume, $directories, $file) = File::Spec->splitpath($File +::Find::dir); my @dirs = File::Spec->splitdir($directories); # unzip any compressed files if ($_[$i] =~ /^(.+?)\.(zip|t?gz|tar|bz2?|tbz)$/i) { # sometimes File::Temp can't clean up properly for (my $x = 0; $x <= $#_; $x++) { my $dir = File::Spec->catfile($File::Find::dir, $_[$x] +); if (-d $dir && $_[$x] =~ /^$1\-EXTRACTED.{5}$/) { rmtree($dir); undef $_[$x]; } }
Does anyone have an idea what the problem might be? I thought it might have something to do with undefining an array element while looping over the array, but I can't reproduce it outside this script.

Replies are listed 'Best First'.
Re: Warning gets the line number wrong?
by merlyn (Sage) on Apr 30, 2007 at 10:47 UTC
    You haven't shown the entire statement that begins on line 416, presuming it's that "if".

    Keep in mind that a statement (including a chain of elsifs) is all considered to begin on its first line, no matter how many lines it spans. So you probably have a <= comparison in some elsif branch that you aren't showing, and one side of that is undef, just as the error says.

      Wow, I never even knew that. I'm sure there's a reason for that and the undef problem mentioned earlier, but that's incredibly annoying.
        Yes, it's annoying, but once you are aware of it (and get used to it), it's not so tough. Here's a simple demo of the basic pattern:
        #!/usr/bin/perl -w $_ = undef; if ( 1 == 2 ) { # this is line 4 print "This cannot happen\n"; } elsif ( $_ < 3 ) { # the problem is at line 7 print "This works okay (but throws a warning)\n"; }
        You'll see that the warning message cites line 4. Simple rule: when a warning points to an "if" statement and makes no sense for that line, check each of the "elsif" statements that relate to that line.
Re: Warning gets the line number wrong?
by jesuashok (Curate) on Apr 30, 2007 at 08:41 UTC
      So that would mean something above that line got optimized out, right? Why doesn't that trigger a warning like "useless use of constant"?
Re: Warning gets the line number wrong?
by DrHyde (Prior) on Apr 30, 2007 at 08:59 UTC
    jesuashok is probably right, but another common cause of broken line numbers in warnings is if you're using a module that is based on a source filter, such as Switch.
Re: Warning gets the line number wrong?
by rodion (Chaplain) on Apr 30, 2007 at 10:33 UTC
    Tracking line numbers for warnings can be tricky. Sometimes it's neccessary to put little progress report warnings in the uncertain area, as in
    warn "before if"; if ($_[$i] =~ /^(.+?)\.(zip|t?gz|tar|bz2?|tbz)$/i) { warn "in if" ... elsif (...) { warn "in elsif 1"; ... else { warn "in else";
    With these in place, you can tell where the "undefined" warning comes in the sequence of execution. It's messy, but you only have to look at it once, for a quick reality check. The debugger is another way to do this, which could be easier or harder, depending on your inclination to switch over to the debugger mindset.
Re: Warning gets the line number wrong?
by naikonta (Curate) on Apr 30, 2007 at 12:46 UTC
    Are sure that each element in @_ is always a defined value? If you know that some elements may be undef and you expect that but can't bear the uninit warnings, just disable selected warning around the block in question. Like,
    no warnings 'uninitialized'; if ($_[$i] =~ /^(.+?)\.(zip|t?gz|tar|bz2?|tbz)$/i) { ... }
    If your Perl is older than 5.6, you can't use no warnings; and use warnings;, but you may consider to upgrade. If you're not able to do so, replace the no warnings line with local $^W = 0;.

    However, if you do care that all elements should have defined values, than you need to test for defined-ness and skip if it fails the test.

    for (my $i = 0; $i <= $#_; $i++) { next unless defined $_[$i] and $_[$i] =~ /^(.+?)\.(zip|t?gz|tar|bz2?|tbz)$/i or $_[$i] =~ .... and so on
    So, if $_[$i] was undefined where $i is at somepoint of iteration, the execution would not even reach the first if.

    And yes, I'd really like to know what happens after that undef $_[$x]. This is not the usual way in constructing multi-level loop. But beyond what you've shown and asked, I sort of believe that the problem lies on your program design. The first obvious indication to me is you need to check on /^(.+?)\.(zip|t?gz|tar|bz2?|tbz)$/i twice. The second is the inner loop on the same array.

    Here's another hint. Working directly on elements of @_ will often give you unexpected results, since $_[$index] is a just reference to the original argument of the corresponding element.

    Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

      Yes, it's kind of weird, but it's a work in progress. The secondary loop and the part about compressed files were shoehorned in there to deal with problems removing temporary directories. You're right that I should clean it up and use a different array variable other than @_, even if just for readability.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://612715]
Approved by jesuashok
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2017-05-26 20:08 GMT
Find Nodes?
    Voting Booth?