Perl-Sensitive Sunglasses PerlMonks

if (\$2) behaves differently than if (defined \$2)

by walto (Pilgrim)
 on Apr 15, 2008 at 17:35 UTC Need Help??

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
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.

Create A New User
Node Status?
node history
Node Type: perlquestion [id://680590]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (4)
As of 2021-01-18 01:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
The STEM quote I most wish I'd made is:

Results (177 votes). Check out past polls.

Notices?