http://www.perlmonks.org?node_id=680590

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

I thought that if (defined $2) is just a better readable way than if ($2). But I found that gives different results:
#!/usr/bin/perl -w # # use strict; my $price = "50,-"; $price =~ m/(\d{1,4}),(\d{0,2})/; if ($2 ) { $price = $1 . "." . $2; } else { $price = $1 . "." . "00"; } print "$price\n";
gives : 50.00 as I would expect
but
if (defined $2 ) { $price = $1 . "." . $2; } else { $price = $1 . "." . "00"; }
gives 50.
Can an enlightend monk explain why?

Replies are listed 'Best First'.
Re: if ($2) behaves differently than if (defined $2)
by moritz (Cardinal) on Apr 15, 2008 at 17:41 UTC
    Since $2 refers to (\d{0,2} it seems that it actually matches zero occurrences of a digit, so $2 is the empty string.

    An empty string is defined, but evaluates to false.

Re: if ($2) behaves differently than if (defined $2)
by starbolin (Hermit) on Apr 15, 2008 at 17:42 UTC

    From perldoc -f defined:

    ' Note: Many folks tend to overuse "defined", and then are surprised to discover that the number 0 and "" (the zero-length string) are, in fact, defined values.'


    s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}

      That's a choice quote. Put another way, the OP is suffering from some confusion that if (defined $x) is intended to be the same as if ($x). In fact, they serve different purposes.

      defined tests whether a variable has any value -- a false value is still a value.

      Short demonstration code:

      my $x; demonstrate(); $x = 1; demonstrate(); $x = 0; demonstrate(); sub demonstrate { if (defined $x) { print "\$x has value $x\n"; } else { print "\$x is undefined\n"; } if ($x) { print "\$x evaluates as TRUE\n"; } else { print "\$x evaluates as FALSE\n"; } print "\n"; }

      This produces the following output:

      $x is undefined $x evaluates as FALSE $x has value 1 $x evaluates as TRUE $x has value 0 $x evaluates as FALSE
      <radiant.matrix>
      Ramblings and references
      The Code that can be seen is not the true Code
      I haven't found a problem yet that can't be solved by a well-placed trebuchet
        Apparently, in Lisp, this is referred to as a semi-predicate problem.

        The very fact that you are using
        if ($2)
        followed by
        $price = $1 . "." . $2
        shows that you are using $2 as a semi-predicate, i.e. to show validity and to hold value.

        Next time, whenever you use if ($var), you should consider if $var needs to be a full-predicate, i.e. strictly a boolean to only show true-or-false.
Re: if ($2) behaves differently than if (defined $2)
by toolic (Bishop) on Apr 15, 2008 at 18:49 UTC
    Aside from your defined issue, it is also a good idea to keep in mind that $1, $2, etc., retain their values from earlier successful pattern matches. Obviously, with your small example, you are only attempting one match. But, with code that attempts several matches, there will be problems unless all match attempts are checked.

    Here is an example to illustrate the point:

    #!/usr/bin/env perl use warnings; use strict; my $str; $str = 'abc def 12'; $str =~ /(\d+)/; print "$1\n" if ($1); $str = 'foo'; $str =~ /(\d+)/; print "$1\n" if ($1); if ($str =~ /(\d+)/) { print "$1\n"; } else { print "no match\n"; }

    prints:

    12 12 no match

    The 2nd "12" is unexpected since the string 'foo' contains no digits.