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

In this piece of code I make the mistake of evaluating if a string equals a numeric value. This is obviously wrong, but why am I still getting inside my if ?
use strict; use warnings; if("test" == 0){ print "in if"; } else { print "in else"; }
The output for this is:
Argument "test" isn't numeric in numeric eq (==) at D:/eclipse/workspa +ce/Tests/shorthand_if/stupid_problem.pl line 4. in if
It seems to me that if a statement is wrong, it should not evaluate to true, what am I missing here ?

Replies are listed 'Best First'.
Re: Why is this evaluating to true?
by lidden (Curate) on Nov 16, 2011 at 13:04 UTC
    The string "test" is zero when perl makes it numeric. I don't remember where that is documented but "test" is zero and e.g. "2test" is two.

      You can use that feature for less-magic numbers in quick scripts. Eg:

      my $time = $minutes / '60 minutes per hour' / '8 hour workdays';
      Aha ! Thanks, good answer !
Re: Why is this evaluating to true?
by roboticus (Chancellor) on Nov 16, 2011 at 13:24 UTC

    pmarcoen:

    The statement isn't necessarily wrong--perl does automatic conversions between numbers and strings, and strings that don't "look like a number" get converted to 0 when you treat them like a number. After all, in a data stream, there may be multiple different data types that you would want to handle differently without lots of explicit type conversions and such. (If you're a fan of explicit conversions, perhaps you should be a Java programmer? </joke>)

    Here's a simple (useless!) example of treating different types of data differently:

    $ cat 938362.pl #!/usr/bin/perl use strict; use warnings; use Scalar::Util qw(looks_like_number); my $t; while ($t = <DATA>) { $t=~s/\s+$//; print "\ninput = '$t'\n"; if (looks_like_number($t)) { print "looks numeric\n"; if ($t == 0) { print "Gotta have somethin' if ya wanna be with me\n"; } else { print "There are $t ways to leave your lover\n"; } } else { print "non-numeric\n"; if ($t eq "Godzilla") { print "Oh, no! There goes Tokyo, go go $t!\n"; } elsif ($t =~ /horse/i) { print "A horse is a horse of course, of course\n"; } else { print "insert song lyric here...\n"; } } } __DATA__ Godzilla 50 A horse of a different color 0 zebra $ perl 938362.pl input = 'Godzilla' non-numeric Oh, no! There goes Tokyo, go go Godzilla! input = '50' looks numeric There are 50 ways to leave your lover input = 'A horse of a different color' non-numeric A horse is a horse of course, of course input = '0' looks numeric Gotta have somethin' if ya wanna be with me input = 'zebra' non-numeric insert song lyric here...

    Since using text strings where numbers are expected is a common logic error, the warnings package tells you when you try to convert a string that doesn't look like a number into a number.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: Why is this evaluating to true?
by JavaFan (Canon) on Nov 16, 2011 at 18:33 UTC
    It seems to me that if a statement is wrong, it should not evaluate to true, what am I missing here?
    What's your definition of wrong? I can think of at least three:
    • Your syntax is incorrect. In that case, it won't compile, it won't run, and it certainly doesn't evaluate to true.
    • You do something Perl cannot do, or has been forbidden to do. Dividing by zero for instance, or dereferencing a string while "use strict 'refs'" is active. In that case, Perl will throw an exception - it will not continue with false (besides, what should be false? A term of the expression? The expression? The block? The current subroutine?). Although one may say that if the exception isn't dealt with, Perl evaluates the entire program to false. ;-)
    • You used the wrong (business) logic. How's Perl supposed to know? You might as well ask Gravity to not shatter the priceless vase if you dropped it by accident instead of intentionally.
    In your case, you used the wrong logic. Perl is kindly enough to warn you "are you sure you want this?", but it has no grounds to declare anything wrong, so it just shoulders on bravely.
Re: Why is this evaluating to true?
by davido (Cardinal) on Nov 16, 2011 at 17:27 UTC

    Time for the obligatory link to perlsyn. Specifically in the Truth and Falsehood section, you will find:

    The number 0, the strings '0' and '' , the empty list () , and undef are all false in a boolean context. All other values are true. Negation of a true value by ! or not returns a special false value. When evaluated as a string it is treated as '' , but as a number, it is treated as 0.


    Dave

Re: Why is this evaluating to true?
by pvaldes (Chaplain) on Nov 16, 2011 at 22:21 UTC
    use strict; use warnings; if('test' eq 0){ print "in if" } else { print "in else" } if(!'test') { print "again in if" } else { print "again in else" } __END__ prints: in else again in else

    All strings in perl are evaluated to true (even the string 'false'!) except this: '0'

    if('0' eq 0) { print "in if" } else { print "in else" } __END__ prints: in if

    the problem here is that you are trying to mix a boolean and a number, this is a logical operation, the same as if(TRUE is FALSE)... not numerical as in if (2*4 == 8), you are trying to say: if (TRUE == 8)

    If you really want to specify that 'this_chain' == zero (the number) and force a numeric comparison you need to comment and deactivate use warnings, (but this is nonsense, use a variable name instead)

    Updated: if ($var == 0) is not a problem for warnings, of course