1

I have some Perl code that's doing something bizarre that I can't figure out. I have two variables defined ahead of this section of code:

$latestPatch = '000';
$test_setup{appl}{Rev0_OK} = 'F';  # a hash element

Both are defined as strings. If I print out the raw variables (wrapping ' around them), 'int($latestPatch)' is '0' and '$test_setup{appl}{Rev0_OK}' is 'F'. So far, as expected. Now I run the following:

$shouldInstall = int($latestPatch) == 0 &&
                 $test_setup{appl}{Rev0_OK} eq 'T';

$shouldInstall ends up with a null value (false/0 expected)! (printing '$shouldInstall' gives ''). Step-by-step debug statements (not shown) indicate that int($latestPatch) == 0 works OK, giving a 1 (TRUE), but $test_setup{appl}{Rev0_OK} eq 'T' is null '' (and thus $shouldInstall is ''). If I change the test to $test_setup{appl}{Rev0_OK} eq 'F', it is 1 (TRUE). If I change the test to $test_setup{appl}{Rev0_OK} ne 'F', it is again null. What's going on here? There are no error messages being issued. I do have boolean variables TRUE and FALSE defined (as int 1 and 0).

aTdHvAaNnKcSe

Phil Perry
  • 2,126
  • 14
  • 18
  • 1
    Re: "I do have boolean variables TRUE and FALSE defined (as int 1 and 0)." Just don't do `... == FALSE` or `... == TRUE`! – ikegami Oct 04 '13 at 16:25
  • I wasn't comparing against my TRUE and FALSE constants. Just `if ($shouldInstall) {...` I was just commenting that I happened to have those constants, in case they had some bearing on the case here. Perhaps I could have been clearer on that. – Phil Perry Oct 04 '13 at 16:43
  • 1
    I know you weren't here; I was giving general advice. People who create `TRUE` and `FALSE` constants tend to check against them, which makes no sense when the language's definition differs from the constants as is the case here. – ikegami Oct 04 '13 at 16:49

2 Answers2

5

$shouldInstall ends up with a null value (false/0 expected)! (printing '$shouldInstall' gives '').

$shouldInstall should end up false, and it does. The empty string is just as false as 0. See this answer explaining what is false.

Most operators return &PL_sv_no for false, which is a scalar containing signed integer 0, floating point 0 and the empty string.

$ perl -MDevel::Peek -e'Dump("a" eq "b")'
SV = PVNV(0x9c6d770) at 0x9c6c0f0
  REFCNT = 2147483647
  FLAGS = (PADTMP,IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
  IV = 0
  NV = 0
  PV = 0x8192558 ""
  CUR = 0
  LEN = 0

If you use it a string, it'll be the empty string. If you use it a number, it'll be zero.

$ perl -wle'print "".("a" eq "b")'

$ perl -wle'print 0+("a" eq "b")'
0

This scalar differs from an empty string in that it doesn't warn when treated as a number.

$ perl -wle'print 0+""'
Argument "" isn't numeric in addition (+) at -e line 1.
0
Community
  • 1
  • 1
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • This is the first time I recall seeing 'true' or 'false' results (including for 'eq' etc. string comparisons) that didn't print out as 1 or 0. It seems odd and inconsistent that I'd get an integer 1 for true and an empty string for false, even if technically they work. – Phil Perry Oct 04 '13 at 16:41
  • 1
    Re: "This is the first time I recall seeing 'true' or 'false' results [...] that didn't print out as 1 or 0.", What did you try?!?!?! `perl -wle'print "a" eq "b"'`, `perl -wle'print 3 == 4'`, `perl -wle'print !1`, etc – ikegami Oct 04 '13 at 16:53
  • Re: "and an empty string for false", You don't get an empty string for false. And technically, you get both integer and string one for true. – ikegami Oct 04 '13 at 16:53
3

The results of those comparisons seem fine: (some form of) true when the 'T'/'F' values match, (some form of) false otherwise.

You seem to be assuming that boolean false will evaluate to an integer 0. There's no reason to expect that.

For example:

$shouldInstall = undef;
print "'$shouldInstall'\n";

$shouldInstall = (1 == 2);
print "'$shouldInstall'\n";

$shouldInstall = "";
print "'$shouldInstall'\n";

$shouldInstall = (1 == 1);
print "'$shouldInstall'\n";

prints:

''
''
''
'1'

as long as you're testing the variable sensibly:

if ($shouldInstall) {
}

you'll be fine.

Paul Roub
  • 36,322
  • 27
  • 84
  • 93
  • Interesting. Every time I've dumped 'true' or 'false' results before, including 'eq' results, I've gotten an integer 1 or 0. So seeing an empty string (?) for a result threw me. – Phil Perry Oct 04 '13 at 16:38