http://qs321.pair.com?node_id=313774

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

This program:
#!/usr/bin/perl -w my $a = 1; my $b = 2; my $c = 3; my $d = 4; my $e; print "$a $b $c $d $e\n";
Produces this output:
Use of uninitialized value in concatenation (.) or string at C:\testpe +rl\undef.pl line 9. 1 2 3 4
While the warning does point me in the right direction, on lines with many variables being used at once, it can take a bit of work to figure out exactly which one is undefined. Is there a way to get more explicit information from warnings like these?

---
A fair fight is a sign of poor planning.

Replies are listed 'Best First'.
Re: Less-than-helpful warnings
by Abigail-II (Bishop) on Dec 10, 2003 at 17:19 UTC
    While the warning does point me in the right direction, on lines with many variables being used at once, it can take a bit of work to figure out exactly which one is undefined. Is there a way to get more explicit information from warnings like these?

    No.

    One should realize that the warning is generated at runtime - not at compile time. At that moment, the name of the variable is hard to get, and (even more important), the undefined value could come from a complicated expression.

    Abigail

Re: Less-than-helpful warnings
by herveus (Prior) on Dec 10, 2003 at 17:18 UTC
    Howdy!

    Off the top of my head, I'd say "no". When you get an "uninitialized variable" warning on a line with a whole bunch of variables, you are just going to have to tease it apart into separate lines to pick out which variable is uninitialized, or something along those lines.

    yours,
    Michael
Re: Less-than-helpful warnings
by jZed (Prior) on Dec 10, 2003 at 20:02 UTC
    Well, not related to your question, and perhaps also less than helpful, but just in case ... you do know that you can get into trouble if you define $a and $b in a script that uses sort?
      Certainly not if $a and $b are lexical, which in this case they are. I'm not even seeing any problem if they are global. Did perl have a problem at some point where the previous values didn't get restored after the sort?

      Update: Sorry, I misunderstood that you were warning against using a sort BLOCK in the lexical scope of $a or $b. If you try, perl will die with an error "Can't use "my $[ab]" in sort comparison".

        To quote from perldoc -f sort: "If you're using strict, you must not declare $a and $b as lexicals. They are package globals."
Re: Less-than-helpful warnings
by Sandy (Curate) on Dec 10, 2003 at 23:44 UTC
    Ditto with all the rest of the replies, except... some strange behaviour.
    Note that if your undefined variable is 1st in the string, no warning message.

    The second print statement does not print a warning.
    Mmmm....

    #!/usr/bin/perl -w my $a = 1; my $b = 2; my $c = 3; my $d = 4; my $e; print "$a $b $c $d $e\n"; print "$e $a $b $c $d\n";
    My guess is that it is the concatenation of a 'null' that causes the warning.

    "$a $b" is optimized to $a." ".$b according to the message I get when I use the 'use diagnostics' with this code.

      The second print gives a warning for me with 5.8.1 and above but not with 5.6.2, so this sounds like a bug that was fixed to me.
      according to the message I get when I use the 'use diagnostics' with this code.

      Since Sprad was looking for better messages "for warnings like these", I think it's worthwhile to emphasize the use diagnostics pragma Sandy mentioned.

      Consider this trivial case:

      #!/usr/bin/perl -w my $a = 1; my $c = 2; print $a + c;

      Without using diagnostics, I get this:

      Unquoted string "c" may clash with future reserved word at test.pl line 5.
      Argument "c" isn't numeric in addition (+) at test.pl line 5.

      However, if I do use it, I get a much more informative error:

      Unquoted string "c" may clash with future reserved word at test.pl line 5 (#1)
      
          (W reserved) You used a bareword that might someday be claimed as a reserved word.
          It's best to put such a word in quotes, or capitalize it somehow, or insert
          an underbar into it.  You might also declare it as a subroutine.
      
      Argument "c" isn't numeric in addition (+) at test.pl line 5 (#2)
      
          (W numeric) The indicated string was fed as an argument to an operator that
          expected a numeric value instead.  If you're fortunate the message
          will identify which operator was so unfortunate.
      

      Sure, in the case I've provided it isn't especially helpful, but it can be useful for tracking down more bizarre errors by giving some suggestions.

Re: Less-than-helpful warnings
by Belmonts (Acolyte) on Dec 10, 2003 at 23:17 UTC
    If it is possible for one of your variables to be undefined I would suggest checking your values before using them. What about joining all you variables into an array, loop through them, and if undefined die with a message about the variable that is undefined?
Re: Less-than-helpful warnings
by mcogan1966 (Monk) on Dec 10, 2003 at 20:15 UTC
    Not to be a "me too", but they are correct. What you get is about all you're going to get. Having recently had to do much error analysis and debugging of a recent project, I can honestly say, though, that Perl does give some good messages, in general. It's just the process of picking apart the code, and the data, to find the "loose thread". Though, the use of <STDOUT> and <STDERR> in Perl have been a major help in that respect. Printing out bits and pieces of data where you can see them will go far to help you realize where the warnings and errors are occuring.
Re: Less-than-helpful warnings
by Sandy (Curate) on Dec 11, 2003 at 00:48 UTC
    print $a," ", $b," ", $c," ", $d," ", $e,"\n";
    produces the following output, which may be more useful
    1 2 3 4 Use of uninitialized value in print at test4.pl line 9.
    In other words, in list context you get better info then when concatenating strings (which is what happens when you "$a $b $c"
      That's going on depend on if/how STDOUT and STDERR are buffered. You won't always see the error in the place where the undefined value is. In fact, when I try, I never do.
Re: Less-than-helpful warnings
by Aristotle (Chancellor) on Dec 11, 2003 at 08:54 UTC

    There is three steps to what happens here: the values from the variables are read, then the various resulting strings are passed to a series of concatenation ops, and finally the result is passed to print.

    The existence of a variable is only apparent in step 1, but reading an undefined value from a value is not and should not elicit a warning. During the concatenation step where the undef is encountered and warned about, its relation to a variable is unknown. You could just as well write

    print 1 . " " . 2 . " " . 3 . " " . 4 . " " . undef;

    From the concatenation operation's point of view, there's no difference to your own code.

    While this situation seems trivial to a human, it is decidedly non-trivial to handle; you would need logic close to a generic partial evaluator to solve this matter.

    Makeshifts last the longest.

Re: Less-than-helpful warnings
by logan (Curate) on Dec 12, 2003 at 03:48 UTC
    The easiest way to figure out which variable is undefined is probably to print them out with a delimiter:
    print STDOUT "|$a|$b|$c|$d|$e|\n";
    If you get
    "1|2||4|5"
    You have an answer. If for some reason you can't simply print out the data, try using the perl debugger. You can step through your program line by line, and display the value of any variable at any time.

    -Logan
    "What do I want? I'm an American. I want more."