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

I'm going through a script trying to make it work with -w. I'm getting a lot of "Use of uninitialized value" errors, but I can't seem to tell how to fix it.
For example, I get the message "Use of uninitialized value in concatenation (.) at mtparse.pl line xxx, <DATA> l ine 1."
The corresponding code looks like:
sub readPorts(\%) { die "Incorrect number of args to readPorts\n" unless @_ == 1; my $portHash = shift; while (<DATA>) { my ($port, $sname, $rem) = split("\t"); push (@{$portHash->{$port}},$sname . "\t" . $rem); } }
The line indicated by the warning is the push(...) statement. I've tried giving explcit values to $port, $name, and $rem before the split to no luck. I also tried giving values to @{$portHash->{$port}}, and $portHash->{$port} and I get the same warning.
What am I not initializing, and how should I do it? I feel like I'm missing something simple here, but it's beginning to feel like I can't see the forest for the trees.

TIA
Guildenstern
Negaterd character class uber alles!

Replies are listed 'Best First'.
Re: Where oh where should I initialize my vars?
by Fastolfe (Vicar) on Oct 25, 2000 at 22:31 UTC
    Perhaps you've hit a line that does not split into 3 pieces separated by tabs? That would make some or all of those variables undefined (uninitialized), generating the warning.
(Guildenstern) RE: Where oh where should I initialize my vars?
by Guildenstern (Deacon) on Oct 25, 2000 at 22:36 UTC
    Okay. I didn't want to do it, since that means 65535 lines of data to look through to verify that all of my tabs were in the right place. However, if I would have paid more attention to the error, I would have seen that it happens on line 1 of __DATA__. Sure enough, line 1 had spaces instead of a tab. Fixed the tab, lost the error.
    /me will be wearing a big "Idiot" sticker on my forehead the rest of the day. *sigh*

    Guildenstern
    Negaterd character class uber alles!
      This sort of thing happens to me quite often, but my choice would be to change your split() to be more flexible (i.e. split on tabs or spaces in this case) if possible, rather than edit your data, unless of course you won't ever need to run this on unknown data in the future. I figure if there is one line of bad data, there's bound to be more sometime (especially since my data have come from manual entry or rather crusty/rusty machinery). Just a thought.
Re: Where oh where should I initialize my vars?
by runrig (Abbot) on Oct 25, 2000 at 22:29 UTC
    The error message seems self explanatory if its the 'push' line. Either $sname or $rem are not initialized. Are there tabs in the input? BTW, the split is more 'correctly' written as:
    my ($port, $sname, $rem) = split /\t/;
          BTW, the split is more 'correctly' written as:
           my ($port, $sname, $rem) = split /\t/;

      Uh... there is nothing wrong with split("\t"). To quote Camel 2 (note that this is different from our own docs for split):

        The /PATTERN/ argument may be replaced with an expression to specify patterns that vary at run-time. (To do run-time compilation only once, use /$variable/o.) As a special case, specifying a space " " will split on whitespace just as split with no argument does. Thus, split(" ") can be used to emulate awk's default behavior, whearas split(/ /) will give you as many null initial fields as there are leading spaces. (Other then this special case, if you supply a string instead of a regular expression, it'll be interpreted as a regular expression anyway.)  

      My point, runrig, is TIMTOWTDI, and that sometimes the 'correct' way isn't the way the programmer wanted to do it. I, for one, like to use quotes around constants that I am splitting on, and slashes for things that look more like regular expressions. Yeah, I know they are the same, but quotes around strings looks better (to me) then slashes.

        Ok, point taken, but in my (perhaps pathetically weak) defense, if that is the official behavior, then it ought to be documented in perlfunc, not just in a book (even if it is The Camel book :-).
Re: Where oh where should I initialize my vars?
by Maclir (Curate) on Oct 26, 2000 at 01:28 UTC
    Others beat me to the punch, in that you were making the assumption that every line in your input file would consist of the three arguments separated by a tab character. This brings up a matter of good programming practice - never assume that the data you are being fed meets the rules. So you need to allow for two situations; the first which you have already found, where there are less than the required number of fields; and the case where there may be more than 3.

    A quick scan through the split documentation says that when called in the scalar context, it will return the count of the substrings. You may want to put a test in first - something like:

    if ( (scalar (split /\t/)) == 3 ) { # Do our stuff } else { print "Bad data", $_; }
    Updated I should not try to program before my first cup of coffee. Yes, fastolfe and runrig picked up the error - the single "=" has been replaced with the "==". (slaps himself silly)
      Ouch. Don't use scalar split. It's marked deprecated, and mangles @_ in the process. Odd that you didn't see that, because you said you were looking through the documentation! {Grin}

      -- Randal L. Schwartz, Perl hacker

        I am having a bad morning here. I checked up the 2nd edition camel - and there was no mention of "deprecated" anywhere, likewise no warning on the @_ mangling either.

        I will now take two asprins and go back to bed.

      Or:
      warn("Bad Data: [$_]"), next unless tr/\t// == 2; # Do Stuff