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

I am reading a files line by line and splitting the string into variables. Sometimes there isn't enough data to put into the variables. Since I just started using the "-w" switch I now know about them, but how do I handle it so that I don't get warnings about uninitialized variables?

Replies are listed 'Best First'.
Re: uninitialized variables
by strat (Canon) on Mar 28, 2002 at 14:55 UTC
    With the function defined, you can test if a variable is defined...

    unless (defined $variable) { # if undefined $variable = 0; # set to standard value }
    or shorter:
    defined $variable or $variable = 0;
    or:
    $variable = 0 unless defined $variable;

    Best regards,
    perl -le "s==*F=e=>y~\*martinF~stronat~=>s~[^\w]~~g=>chop,print"

        > $variable ||=0;

        This will work as long as $variable is not an empty string. I think, in perl6 there will be something like
        $variable //= 0;
        just for cases like that.

        Best regards,
        perl -le "s==*F=e=>y~\*martinF~stronat~=>s~[^\w]~~g=>chop,print"

      Checking for undefined values looks like the way to go. I'm going to add this to my code. Thank you all for the quick responce.
Re: uninitialized variables
by ferrency (Deacon) on Mar 28, 2002 at 15:03 UTC
    Another way to solve this is simply to initialize the variables before your split().

    For example, I'm assuming your code looks something like this currently:

    my ($this, $that, $other) = split (/\s+/, $line); # $line might have < 3 elements in it, the rest will be undef
    If you initialize your variables with non-undef's first, you'll avoid the "not defined" warnings:

    my ($this, $that, $other) = ("") x 3; ($this, $that, $other) = split (/\s+/, $line); # Now the worst case is you'll have a null string, not undef
    Alan
Re: uninitialized variables
by dragonchild (Archbishop) on Mar 28, 2002 at 15:24 UTC
    Another way is to do something like:
    my ($x, $y, $z) = map { $_ || '' } split;
    Since undef is false in a boolean context, it will assign the empty string to variables that are undefined.

    Note: This will also assign the empty string instead of zero or the string containing zero. Those also evaluate as false in a boolean context. If you just want to replace the undefined strings, do something like:

    my ($x, $y, $z) = map { defined $_ ? $_ : '' } split;

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

Re: uninitialized variables
by RMGir (Prior) on Mar 28, 2002 at 15:01 UTC
    IF (and ONLY if) you can handle a default value ok, you could do something like this:
    while(<>) { my ($x, $y, $z) = (0,0,0); ($x, $y, $z)=split; # do whatever }
    Or you could
    get silly, and do something like:
    while(<>) { my @flds=split; my ($x, $y, $z)=(@flds,0,0,0); # do whatever }
    But then you have to be ready to handle 0's (or whatever other default you chose) when data is missing, and you have to make sure you don't pick a default value that could be real data.

    It's much safer to use defined and know when your fields are missing; that way you get something like real NULL handling, in the SQL sense.
    --
    Mike

    Edit: thanks to ariels for the correction!

      There's a subtle difference between the 2 forms you suggest: only the second works!

      When you say

      my ($x, $y, $z) = (0,0,0); ($x, $y, $z)=split;
      you always set $x, $y and $z! That's what assignment is all about!

      Here it is in the debugger:

      main::(-e:1):   0
        DB<1> ($x,$y,$z)=(2,3,4)
      
        DB<2> ($x,$y,$z)=split ' ',"two words"
      
        DB<3> x $x
      0  'two'
        DB<4> x $y
      0  'words'
        DB<5> x $z
      0  undef
      

      The second works, because it isn't trying to reassign undef.

Re: uninitialized variables
by the_slycer (Chaplain) on Mar 28, 2002 at 16:05 UTC
    All the above are good and probably the recommended way to do things. However, here's another option that I've used in the past.

    Instead of using the -w switch, try use warnings (just like use strict). Then, in situations where you *know* that the data might not be there turn warnings off with no warnings before assigning to your variables. Once that bit of code is done, turn it back on using use warnings again.

    Maybe not the best way, but convienient when you have a whole whack of variables that you might be assigning to, and don't want to initialize them all to "0".