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

Debugging "Use of uninitialized value" warnings.

by cwry (Monk)
on Apr 04, 2007 at 02:56 UTC ( [id://608191]=perlquestion: print w/replies, xml ) Need Help??

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

In the following code (contrived for illustration):

use strict; use warnings; my %foo; my %bar; $bar{'one'} = 1; my $x = "$bar{'one'} $foo{'one'}";

Here I am making the deliberate mistake of not initializing $foo{'one'}, and of course I receive:

Use of uninitialized value in concatenation (.) or string at test.pl line 7.

If I receive this warning in a non-trivial program, I can go back and insert some debugging code to check which one of $bar{'one'} or $foo{'one'} is unitialized.

However, is there a way I can direct perl to automatically tell me which of the two (or more) interpolated values were unitialized?

Desired sample output:

Use of uninitialized value ($foo{'one'}) in concatenation (.) or string at test.pl line 7.

If the above is not possible, are there any recommended alternatives? I want to be able to catch (and understand) warnings like this without resorting to rerunning the program with additional tracer code (data dumping, et cetera).

Is the best practice simply to code more defensively and explicitly check all variables are initialized prior to interpolation? I could do that, I guess, but I'm afraid of bloating the code needlessly.

Replies are listed 'Best First'.
Re: Debugging "Use of uninitialized value" warnings.
by dave_the_m (Monsignor) on Apr 04, 2007 at 09:55 UTC
    This is not currently possible. However, the development version of perl (from 5.9.2 onwards) attempts to determine which variable was undefined; it can't always, as this example shows:

    use strict; use warnings; my %foo; my %bar; $bar{'one'} = 1; my ($x,$y); $x = "$bar{'one'} $foo{'one'}"; $x = "$y $foo{'one'}"; $x = "xxx $foo{'one'}"; __END__ Use of uninitialized value in concatenation (.) or string at /tmp/p li +ne 10. Use of uninitialized value $y in concatenation (.) or string at /tmp/p + line 11. Use of uninitialized value in concatenation (.) or string at /tmp/p li +ne 11. Use of uninitialized value $foo{"one"} in concatenation (.) or string +at /tmp/p line 12.
    Dave.
Re: Debugging "Use of uninitialized value" warnings.
by Tobiwan (Beadle) on Apr 04, 2007 at 11:20 UTC
    Hi, there is no simple way to do that and the exact behavior as described I can't emulate (today). I believe, that it's possible with deeper knowledge in perlXS, to access the exact codeline which throw the warning and extract their content. But you can define a signalhandler and use PadWalker to print out the lexical and global variables. The following example output these warnings:
    Warning: Use of uninitialized value in concatenation (.) or string at mpu.cgi line 25.
    Possible variables are:
              '$GLOBAL_VARIABLE' => \'global',
              '$t' => \undef,
              '$s' => \'regular output'
    
    #!/usr/bin/perl use strict; use warnings; use PadWalker(); use Data::Dumper(); local $SIG{'__WARN__'} = sub { if($_[0] !~ /^Use of uninitialized value/) { print @_; } else { # If there are objects, the output can be VERY large when you +increase this local $Data::Dumper::Maxdepth = 2; # takes all lexical variables from caller-nemaspace my $possibles = Data::Dumper::Dumper({ %{PadWalker::peek_my(1) +}, %{PadWalker::peek_our(1)} }); $possibles ne "\$VAR1 = {};\n" ? ($possibles =~ s/^.*?\n(.*)\n +.*?\n$/$1/ms) : ($possibles = ''); print STDERR "Warning: " . join(', ', @_) . "Possible variable +s are:\n$possibles\n"; } }; our $GLOBAL_VARIABLE = 'global'; sub mySub { my $t = undef; my $s = "regular output"; print " $s $t "; } mySub();
    Warnings abouot uninitialized values are resolved, all others behave like before. This you should use only to develop. Some warings about uninitialized variables can be very large, when the caller-namespace contain many variables. Tobiwan
Re: Debugging "Use of uninitialized value" warnings.
by NovMonk (Chaplain) on Apr 04, 2007 at 13:01 UTC
    I hope someone eventually answers this part of your question:

    Is the best practice simply to code more defensively and explicitly check all variables are initialized prior to interpolation? I could do that, I guess, but I'm afraid of bloating the code needlessly.

    because this drives me nuts, too. I am still very new to perl, at the stage where those warnings Do look like "noise" to me. I don't understand why I should have to explicitly set all my variables to a value to avoid this problem. If indeed, that's what I need to do. Particularly when the resulting output is what I want.

    If anyone could point me toward some relevant pages here or in the Llama/ Camel books explaining this, I'd be very grateful.

    Pax,
    NovMonk

      3rd Edition of the Camel, first paragraph of chapter 4, p.111 discusses this.
      Perl does not force you to program in any particular style, but most experienced programmers have made enough mistakes to know that initialising variables, like use warnings and use strict, are a Good Thing.
      Strangely I can't find a direct 'Best Practice' to initialize variables in TheDamian's book.

      NovMonk: You'll need to read about warnings (perldoc -f warn) but this may also help.

      This generates a compile-time error if you access a variable that wasn't declared via use vars, localized via my or wasn't fully qualified.

      In (perhaps oversimplified) words, Perl is exhibiting a bit of DWIMery here; "protecting you from yourself" or "helping you catch mistakes like typos in a $var name (eg $var somehow is typoed as $vqr

      ps: take the advice at the top of that page, and use perldoc to obtain a fuller explation.

Re: Debugging "Use of uninitialized value" warnings.
by gloryhack (Deacon) on Apr 04, 2007 at 04:17 UTC
    Defensive code is the difference between fragility and robustness.

      Agreed. I generally try to code defensively, but in the context of my original question, I am trying to make the defensive code implicit (Perl automatically tells me when and where I used an uninitialized variable) rather than explicit (adding code to check if a variable is unitialized then dying/warning if it is).

      Both have the same result, but I think the former results in cleaner code.

        It'd be a handy feature to have, certainly, but I'm not aware of any easy way to get it. If there were a pragma to turn on verbose warnings of that kind, I'd have a new love.

        My wife might not like it, though, because I'd spend all of my days and nights just gazing lovingly at perl...

Re: Debugging "Use of uninitialized value" warnings.
by f00li5h (Chaplain) on Apr 04, 2007 at 03:02 UTC

    use Data::Dumper; print Dumper [ $bar{'one'}, $foo{'one'} ];
    will tell you which one is undef.

    @_=qw; ask f00li5h to appear and remain for a moment of pretend better than a lifetime;;s;;@_[map hex,split'',B204316D8C2A4516DE];;y/05/os/&print;

      Thanks, but that's not what I'm after. As I said originally:

      if I receive this warning in a non-trivial program, I can go back and insert some debugging code to check which one of $bar{'one'} or $foo{'one'} is unitialized.

      What I want (as I said), is to have Perl automatically tell me which of the two were uninitialized within the warning, without resorting to inserting additional debug code (as is the case of using Data::Dumper)

Re: Debugging "Use of uninitialized value" warnings.
by Spidy (Chaplain) on Apr 05, 2007 at 03:01 UTC
    Why not try swapping line 7 to something like this?
    my $x = $bar{'one'}; $x .= " $foo{'one'}";
    That way if there IS an uninitialized variable error, you'll be able to tell which variable it is based on the line number returned.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (3)
As of 2024-04-23 23:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found