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

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

use strict; use warnings; my $incr=0; my $incr1=0; my @need = qw(sanjay samir sanjay sudha jasmin sanjmay); my @array1=""; for(;;) { last if $need[$incr] eq ''; if ($need[$incr]=~ qr/^sanj/) { $array1[$incr1]= $need[$incr]; $incr1++; } $incr++; } print @array1;
When i run this program it shows
Use of uninitialized value in string eq at test10.pl line 9
sanjaysanjaysanjmay
Plz. suggest me some suitable code to avoid the above warning?

Replies are listed 'Best First'.
Re: Why "use of uninitialized value" warning comes?
by Corion (Patriarch) on Nov 01, 2006 at 12:25 UTC

    When looking at line 9 in your source code, there is a string eq test. That warning warns you that you are using a value ($need[$incr]) in a string equality test (eq '') and that value is undefined. Maybe you are confused how to iterate over an array. for(;;) is not the way to iterate over an array. And while all elements of an array after its defined length will be equal to the empty string, that will produce the warning, as all accesses to an array outside its defined length return undef. If you are doing array manipulation, you want to read foreach and push.

    Your loop can be written even shorter by using grep:

    my @array1 = grep { /^sanj/ } @need;
      Or even
      for my $need (grep { /^sanj/ } @need) { $array1[$incr1++] = $need; } #although maybe in that case you would just do the more readable for my $need (@need) { if($need =~ /^sanj/) { $array1[$incr1++] = $need; } }
      And to make that warning go away in places you really need the eq there is if(defined $foo && $foo eq 'bar')

                      - Ant
                      - Some of my best work - (1 2 3)

Re: Why "use of uninitialized value" warning comes?
by davorg (Chancellor) on Nov 01, 2006 at 12:44 UTC

    This warning seems quite clear to me. It says that you are doing a string comparison with an undefined value. You are only doing one string comparison in this code (and I assume that's on line 9). The comparison looks like this:

    $need[$incr] eq ''

    The empty string isn't undefined, so it must be that the value in $need[$incr] becomes undefined at some point. This is almost certainly caused by your unconventional looping mechanism. I think that you think that once you go past the end of the @need array then your string comparison will be true and your loop will exit. And that is what is happening, but when you go past the end of an array, the next (non-existant) element is "undef", not the empty string. Now, in a string comparison, "undef" is converted to the empty string, but that conversion isn't silent and you'll get that warning to tell you what Perl has done.

    To avoid the warning, check that $needs[$incr] is defined, not that it is an empty string. Actually this whole approach is a little fragile as an array can contain undefined elements (and empty strings) and your loop could finish early. You might be better off using a foreach loop to iterate across the array.

    Perl's warning and error messages are generally far clearer that the ones that you get from many other languages. If you read them carefully then you can usually work out what they are trying to tell you. If you need more help, then look at the perldiag manual page or add use diagnostics to your program (but remove it again once the program is finished).

    --
    <http://dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: Why "use of uninitialized value" warning comes?
by reneeb (Chaplain) on Nov 01, 2006 at 12:22 UTC
    use strict; use warnings; my $incr=0; my @need = qw(sanjay samir sanjay sudha jasmin sanjmay); my @array1; for my $elem(@need) { if ($elem=~ qr/^sanj/){ push @array1,$elem } } print @array1;
      qr/^sanj/ should be /^sanj/
Re: Why "use of uninitialized value" warning comes?
by liverpole (Monsignor) on Nov 01, 2006 at 15:07 UTC
    There's an idiom I often use when I want to ignore undefined values:  ($variable || 0).

    You could use that in your code like this:

    last if ($need[$incr] || 0) eq '';

    Simply put, that means:  "last if $need[$incr] is undefined -or false".

    It works well when you want to temporarily map undefined values to false for the purposes of a test.

    Update:  Having said that, I want to point out that what others have said above about your for(;;) loop is correct, it is unconventional, and might give you problems if you were iterating over a list which potentially had false values in it.  It's important that you understand why you are getting any warnings, and only "workaround" them once you're convinced that it's appropriate to do so.


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/

      What if an element of @need was the nul string ("")? If you want to check if you've reached the end of the array, check if you've reached the end of the array.

      last if $incr == @need;