Binarus Binarus - 11 months ago 127
Perl Question

Warning about uninitailized variable despite check for undef

I seem to be very silly today, or I have a very weird problem. Please consider the following code:

#!/usr/bin/perl

use strict;
use warnings;
use warnings::unused;
use warnings FATAL => 'uninitialized';

my ($String, $Pattern);

$Pattern = "pattern";
$String = "pattern\n";

if (($String =~ m/^([^\ ]+).*$/s) &&
defined($1) &&
($1 =~ m/^.*$Pattern$/s)) {

print $1."\n";
}


This code produces the following warning (and then stops because of
use warnings FATAL => 'uninitialized';
):

Use of uninitialized value $1 in concatenation (.) or string at [...]


I really don't understand this because I am testing if
$1
is defined (initialized) before using it. The culprit seems to be the last condition line (i.e.
($1 =~ m/^.*$Pattern$/s)
). If I leave this away, the warning is gone.

But why? According to my understanding, that line should just test
$1
, but not change its value (
$Pattern
and the rest of that RegEx don't contain parentheses, so
$1
should not be re-assigned a possible match).

Hmmm ... while thinking about it, it comes to my mind that Perl might set
$1
and its colleagues in every case when a RegEx is matching, whether or not there are parentheses in the RegEx. This would explain the behavior. Is it true?

Answer Source

I'm creating an answer from my comments above:

if (($String =~ m/^([^\ ]+).*$/s) && # If matching, this will set $1
    defined($1) &&                   # Here $1 is still defined
    ($1 =~ m/^.*$Pattern$/s)         # If matching, will reset all $1, .. vars
) {

So, whenever a regex matches, it will reset all digit variables (and other regex related variables).

The only solution I see is to split the condition up and save $1 in an extra variable. Which is usually a good thing, anyway.

if ($String =~ m/^([^\ ]+).*$/s and defined $1) {
    my $match = $1;
    if ($match =~ m/^.*$Pattern$/s) { ... }
}

Note that in this case you don't even have to check for defined $1 because if this pattern matches, $1 will be always defined. It depends on the pattern.

perldoc perlvar:

$<digits> ($1, $2, ...)
        Contains the subpattern from the corresponding set of capturing
        parentheses from the last successful pattern match [...]
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download