Reputation: 25996
I have this code
#!/usr/bin/perl
use warnings;
use strict;
my $nis = "qqq";
my $grp = "pre-qqq";
if ($nis eq $grp || 'pre-' . $nis eq $grp) {
print "match1\n";
}
if (($nis || 'pre-' . $nis) eq $grp) {
print "match2\n";
}
where the first if
-statement works, but the second doesn't.
What is wrong with the second?
Can it be done without repeating the variables twice?
Upvotes: 2
Views: 237
Reputation: 11
strpos returns the index position of where it first found the $needle, which could be 0. Since 0 also resolves to false the solution is to use strict comparison: if( false !== strpos( $haystack, $needle )...
Upvotes: 1
Reputation: 46187
Because the first makes (potentially) two comparisons, first comparing $nis
to $grp
and, if that fails, comparing 'pre-'.$nis
to $grp
, while the second will only ever make a single comparison, of $nis || 'pre-'.$nis
against $grp
.
Your problem is that $nis || 'pre-'.$nis
is not a quantum superposition which can take either value depending on how you look at it, it is a single value of either $nis
or 'pre-'.$nis
. If $nis
is truthy (which is to say, it is not an empty string, undef, the number 0, or the string "0"), then that value will be $nis
. If not, that value will be 'pre-'.$nis
(which, given the truthiness rules, means that 'pre-'.$nis
will only ever be either 'pre-'
or 'pre-0'
).
If you want to compare against two values, you generally need to make two comparisons... but you can do this particular comparison in one step by making the value you test against a regular expression:
if ($grp =~ /^(:?pre-)?$nis/) {
print "match3\n";
}
I'd stick with the with your first comparison, though, for the sake of readability.
Upvotes: 5
Reputation: 98398
if ( $grp ~~ [ $nis, "pre-$nis" ] ) {
print "match\n";
}
or (pre-5.10.1)
if ( grep $_ eq $grp, $nis, "pre-$nis" ) {
print "match\n";
}
Upvotes: 2
Reputation: 19981
What's wrong is that "(A or B) equals C" and "(A equals C) or (B equals C)" mean completely different things. In your second if
, you've asked Perl first to compute $nis || 'pre-'.$nis
and then to see whether it equals $grp
.
Computing $nis || 'pre-'.$nis
(kinda) treats $nis
and 'pre-'.$nis
as boolean (true/false) values. More precisely, the result equals $nis
if that's not a value Perl considers "false"; otherwise it equals 'pre-'.$nis
. In this case, "qqq"
is not false, so the value is just "qqq"
. Since this doesn't equal $grp
, the condition in your second if
is false.
In ordinary language, if you say "Either 3 or 6 is prime" or "Either Joe or Bob is Ellen's brother", a human listener will interpret that in the way I think you want your second if
to be interpreted. But that's not how any computer language I know of works. (Semi-exception: Grisworld's "Icon".)
Upvotes: 4
Reputation: 10940
($nis || 'pre-' . $nis) evaluates to 'pre-' . $nis only if $nis is either not defined, 0, or an empty string. so in your case, it's always evaluated as if ($nis eq $grp) { ... stick with your first approach, and you will be fine
Upvotes: 1