Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 673
Binarus Avatar asked Dec 02 '22 12:12

Binarus


1 Answers

perldoc perlvar:

Contains the subpattern from the corresponding set of capturing parentheses from the last successful pattern match, not counting patterns matched in nested blocks that have been exited already.

Since the second match is the last successful pattern match, inside the if block $1 is undef.

You could do:

my ($match) = ($String =~ m/^([^\ ]+).*$/s);
if (defined $match && $match =~ m/^.*$Pattern$/s) {
    print $match."\n";
}
like image 71
ysth Avatar answered Dec 26 '22 14:12

ysth