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

Hi Monks!

I have this line of code generating a warning ("Use of uninitialized value in pattern match (m//)") and I can't understand why, since I am initializing the variable if there is no match. Can I get some explanation why?
Here is the line of code:

if($value_a =~/personal/){$value_a= "checked";}else{$value_a = "";}

The value of $value_a is coming from a database, it could be empty, if in the database it would have no data for this variable. Shouldn't the line of code above by not having a match in the "if" assign a value=""(empty)to $value_a?

Thanks!

Replies are listed 'Best First'.
Re: Uninitialized Value Question
by philcrow (Priest) on Feb 27, 2007 at 17:07 UTC
    Yes, it will assign the blank string. But the warning is for mentioning an undefined value in the if test itself. It is only a warning. You should try to quite the warning with something like this:
    if ( defined $value_a and $value_a =~ /personal/ ) {...
    Either that, or say something like this before the if:
    $value_a ||= '';

    Phil

      I'd write that initialization as:

      defined($value_a) or $value_a = '';
      The ||= op will convert zero to an empty string, which may provide surprises. There is the shiny new //= (I think it is) op to do that, but in the interest of portability I wouldn't use it yet.

      After Compline,
      Zaxo

        Fair enough, but I favor changing the if condition as in my first example. And, in the OP's code any value (including zero) was going to become the empty string when the regex failed.

        But the subtle problem you raise could well bite others. I'm also looing forward to //= installed most everywhere.

        Phil

      Yes, it will assign the blank string. But the warning is for mentioning an undefined value in the if test itself. It is only a warning. You should try to quite the warning with something like this:
      if ( defined $value_a and $value_a =~ /personal/ ) {...

      And one minor modification that no one seems to have mentioned yet would be to "factor" out the assignment with the ternary C<?:> operator, which also makes for a more concise but still fairly readable (actually, more readable IMHO) syntax like thus:

      $value_a = defined $value_a && $value_a =~ /personal/ ? 'checked' : '' +;

      Since in both cases $value_a would appear quite a number of times, and that makes the whole thing less readable, well at least for me, I feel like using a pronoun instead, that is a C<for> loop's aliasing property. In the second case this "trick" can easily be cast in the form of a statement modifier:

      $_ = defined && /personal/ ? 'checked' : '' for $value_a;

      But readability is such a subjective matter and this use so controversial that I won't certainly insist on it.

Re: Uninitialized Value Question
by davorg (Chancellor) on Feb 27, 2007 at 17:11 UTC

    If your database column contains a NULL in this column then $value_a will contain the Perl value "undef". The warning you are getting is saying that you are trying to match a regular expression against an undefined variable.

    You probably want to change the code to something more like this:

    if (defined $value_a) { if($value_a =~/personal/) { $value_a = "checked"; } else { $value_a = ''; } } else { $value_a = ''; }

    You should also consider whether you really want to check the value of the variable using a regex match. If you just want to check that the value is "checked", then using the string equality operator will be more efficient.

    if (defined $value_a) { if($value_a eq 'personal') { $value_a = 'checked'; } else { $value_a = ''; } } else { $value_a = ''; }

    Update: Fixed a couple of typos (thanks johngg)

Re: Uninitialized Value Question
by graff (Chancellor) on Feb 28, 2007 at 01:48 UTC
    So, you're trying to make sure that null values coming back from the database get turned into unobtrusive empty strings in your script, so that you stop seeing these pesky warnings. Others have provided different alternatives to what you posted, but my favorite differs from those -- to wit:
    $value_a = ( !defined( $value_a )) ? '' : ( $value_a =~ /personal/ ) ? 'checked' : $value_a;
    This assumes that there might be some non-null values that don't match /personal/, and those should be left as-is. If it's actually just null/non-null issue, you could simplify that further:
    $value_a = ( !defined( $value_a )) ? '' : 'checked';
Re: Uninitialized Value Question
by Moron (Curate) on Feb 27, 2007 at 17:23 UTC
    Your initialisation effort happens after the error occurs. But I really wanted to stick my oar in here because technically speaking my $fred = undef() counts as an initialisation to an undefined value, so the error ought to say undefined instead of uninitialised or maybe someone already tried to correct the same implied confusion from that, in which case perhaps "(re-) undefined" would finally catch it all.

    -M

    Free your mind

    A reply falls below the community's threshold of quality. You may see it by logging in.