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

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

Dear Monks,

I recently was surprised that a ascii '0' was interpreted by an if statement as 'FALSE'. I have thought about this alot, and wonder if this really the way it should be.

The following script shows what I'm talking about.

use strict; my $var = 0; if ( $var ) { print "$var True\n"; } else { print "$var + False\n"; } undef $var; if ( $var ) { print "undef True\n"; } else { print "und +ef False\n"; } my $var1 = ''; if ( $var1 ) { print "'$var1' True\n"; } else { print +"'$var1' False\n"; } my $var2 = ""; if ( $var2 ) { print "\"$var2\" True\n"; } else { prin +t "\"$var2\" False\n"; } my $var3 = '0'; if ( $var3 ) { print "\t'$var3' True\n"; } els +e { print "\t'$var3' False\n"; } my $var4 = "0"; if ( $var4 ) { print "\t\"$var4\" True\n"; } e +lse { print "\t\"$var4\" False\n"; } if ( $var4 == 0 ) { print "\t\"\$var4\" True\n"; } else { prin +t "\t\$var4\" False\n"; } if ( $var4 eq '0' ) { print "\t\"\$var4\" True\n"; } else { pr +int "\t\"\$var4\" False\n"; } print "\t","\"\$var4\" has length of ",length($var4)," and ASC +II value of ",ord($var4),"\n"; my $var5 = '1'; if ( $var5 ) { print "'$var5' True\n"; } else { print +"'$var5' False\n"; } my $var6 = "1"; if ( $var6 ) { print "\"$var6\" True\n"; } else { prin +t "\"$var6\" False\n"; } my $var7 = 1; if ( $var7 ) { print "\"$var7\" True\n"; } else { prin +t "\"$var7\" False\n"; }
The script produces:
0 False undef False '' False "" False '0' False '0' False "$var4" True "$var4" True "$var4" has length of 1 and ASCII value of 48 '1' True "1" True "1" True

The first 4 and the last 3 lines I agree with, but the lines in the middle I have a problem with.

I checked several of my perl books and it seems:

But then in "Programming Perl" Glossary is states 'false In Perl, any value that would look like "" or "0"...' but this disagrees with the definition on page 7.

Am I missing something or has it just been too long of a perl week?

Thank you

"Well done is better than well said." - Benjamin Franklin

Replies are listed 'Best First'.
Re: What is the correct definition of False and Null in Perl?
by davido (Cardinal) on Oct 07, 2011 at 22:38 UTC

    Maybe just a long day. Here are four good explanations from trusted sources.

    But how does Perl decide whether a given value is true or false? Perl doesn’t have a separate Boolean datatype, like some languages have. Instead, it uses a few simple rules:

    • If the value is a number, 0 means false; all other numbers mean true.
    • Otherwise, if the value is a string, the empty string ('') means false; all other strings mean true.
    • Otherwise (that is, if the value is another kind of scalar than a number or a string), convert it to a number or a string and try again.

    There’s one trick hidden in those rules. Because the string '0' is the exact same scalar value as the number 0, Perl has to treat them both the same. That means that the string '0' is the only non-empty string that is false.

    Randal L. Schwartz; brian d foy; Tom Phoenix. Learning Perl, 6th Edition (Kindle Locations 1895-1904). O'Reilly Media.

    And...

    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.

    perlsyn, Truth and Falsehood

    And of course there's the Camel book you referred to:

    Truth in Perl is always evaluated in a scalar context. Other than that, no type coercion is done. So here are the rules for the various kinds of values a scalar can hold:

    1. Any string is true except for "" and "0".
    2. Any number is true except for 0.
    3. Any reference is true.
    4. Any undefined value is false.

    Larry Wall; Tom Christiansen; Jon Orwant. Programming Perl, 3rd Edition (Kindle Locations 1991-1995). O'Reilly Media.

    The Perl Cookbook delivers a brief explanation as to "why."

    Two defined strings are false: the empty string ("") and a string of length one containing the digit zero ("0"). All other defined values (e.g., "false", 15, and \$x) are true. You might be surprised to learn that "0" is false, but this is due to Perl's on-demand conversion between strings and numbers. The values 0., 0.00, and 0.0000000 are all numbers and are therefore false when unquoted, since the number zero in any of its guises is always false. However, those three values ("0.", "0.00", and "0.0000000") are true when used as literal quoted strings in your program code or when they're read from the command line, an environment variable, or an input file.

    This is seldom an issue, since conversion is automatic when the value is used numerically. If it has never been used numerically, though, and you just test whether it's true or false, you might get an unexpected answer—Boolean tests never force any sort of conversion. Adding 0 to the variable makes Perl explicitly convert the string to a number:

    Tom Christiansen; Nathan Torkington. Perl Cookbook, 2nd Edition (Kindle Locations 2815-2825). O'Reilly Media.

    I bolded the most important part of that last excerpt.


    Dave

      There are some special case true/false situations!

      (1) In Perl, the string: "0 but true" is an exception. This string will evaluate to a numeric 0, but a logical true! The logical "true" is not surprising, but the numeric 0 is! That is because this is a special case coded into Perl. Even under use strict; use warnings;, "0 but true" can be used in a numeric expression/computation.

      #!/usr/bin/perl -w use strict; my $x = "0 but true"; print $x + 1; #prints 1!!! my $xx = "1 but true"; # print $xx +1; #Ooops ERROR! #non-numeric addition!
      (2) There is a more "modern way" of returning the "0 but true" value. That is the string "0E0". The DBI will return this to mean: "hey, I worked!, but I modified zero rows". 10**0 is one. So 0*10**0=0*1=0. So this enables the conveyance of (a)I worked (no error) and (b)result is zero within a single string value "0E0".

      I have not seen recent code with the case (1) above. But I have verified that it does indeed work. You don't have to get too far into the DBI before you encounter (2) like when you are updating a table - the table update was just fine "true", but it just didn't do anything (rows modified = 0).

        > That is because this is a special case coded into Perl.

        every string starting with a number (plus leading whitespaces) evaluates to that number.

        The only specialty about "0 but true" are the missing messages under "warnings".

        DB<102> $a=" 41 The ultimate answer!" DB<103> print ++$a 42

        I would rather prefer "0.0" or "0E0", if I was calling functions in scalar context.

        Cheers Rolf

      Your reference to the "The Perl Cookbook" was what I needed. I checked my copy and on page two is the definition, and I even had the phrase highlighted.

      "Two defined strings are false: the empty string ("") and a string of length one containing the digit zero ("0")."

      Thank you

      "Well done is better than well said." - Benjamin Franklin

      > Adding 0 to the variable makes Perl explicitly convert the string to a number:

      However there is still confusion with some number formats like hexadecimal, because Perl only converts strings which represent integers or floats as decimals! (see perlnumber).

      just run

      $a="0x10"; ++$a;

      and in Perl $a is now 1 in JS it's 17!

      Cheers Rolf

      UPDATE: OTOH JS obviously can't handle octals the same way:

      repl> $a=010; ++$a 9 repl> $a="010"; ++$a 11

        I redid your code, dropping the quotes as:

        $a=0x10; ++$a; print "$a\n";

        And the result was 17 (perl5.10.1 and perl5.12.2), which I think was what you wanted.

        P.S. I am amazed how many good comments have come from this question and the PM answers.

        Thank you

        "Well done is better than well said." - Benjamin Franklin

Re: What is the correct definition of False and Null in Perl?
by ikegami (Patriarch) on Oct 08, 2011 at 07:20 UTC

    Zero (in any format), the empty string and undef are false, as documented in perlsyn. Objects can also evaluate to false through overloading.

    The reason zero in every format must be false is quite simple. If zero in some formats is false and zero is some other formats is true, something false could became true just by looking at it because Perl is free to convert between equivalent representations. That would be very bad.

    That means that signed integer (IV) zero is false, unsigned integer (UV) zero is false, floating point (NV) zero is false, basic string (PV,UTF=0) zero is false, and wide string (PV,UTF8=1) zero is false.

    PS — I don't know which Perl book talked of "null value" and "null variable", because Perl has no such thing. Perhaps you mean undef?

        Not really. Many strings become zero when converted as a number, but until they've been converted, Perl doesn't consider them zero. This includes "abc" and those you listed.

        You'll never get those strings from stringifying zero, so there's no problem.

      Your internal description is appreciated. I re-checked my use of 'null' and it was used in a perl book comparing perl to C.

      I totally missed the definition of false as previously noted.

      Thank you

      "Well done is better than well said." - Benjamin Franklin

Re: What is the correct definition of False and Null in Perl? (OT: Formatting of OP)
by ww (Archbishop) on Oct 07, 2011 at 23:52 UTC

    It would be nice if the code your next post is self-consistent and reasonably indented. Did someone suggest that you get bonus points for using fewer lines and less white space? If so, whack that someone for giving you a bum steer... and make your next post readily readable. It'll help you get answers.

    Also, consider your output: labeling make it easier to read and understand. Your tabs in the lines with which you disagreed was a big step in the right direction but consider how labeling makes the way you wrote your $var...s easier to know, from the output alone.

    Something like this may serve as an example:

    #!/usr/bin/perl use strict; use warnings; # 930247 my $var = 0; if ( $var ) { print "\$var ($var) True\n"; } else { print "\$var ($var) False\n"; } undef $var; if ( $var ) { print "\$var (undef) True\n"; } else { print "\$var (undef) False\n"; } my $var1 = ''; if ( $var1 ) { print "\$var1 ('') True\n"; } else { print "\$var1 ('') False\n"; } my $var2 = ""; if ( $var2 ) { print "\$var2 (\"\") True\n"; } else { print "\$var2 (\"\") False\n"; } my $var3 = '0'; if ( $var3 ) { print "\t \$var3 ($var3 - as a single-quoted number) True\n"; } else { print "\t \$var3 ($var3 - as a single-quoted number) False\n"; } my $var4 = "0"; if ( $var4 ) { print "\t \$var4 ($var4 - as a double-quoted number) True\n"; } else { print "\t \$var4\ ($var4 - as a double-quoted number) False\n"; } if ( $var4 == 0 ) { print "\t \$var4 ($var4 - as an unquoted number) True\n"; } else { print "\t \$var4 ($var4 - as an unquoted number) False\n"; } if ( $var4 eq '0' ) { print "\t \$var4 ($var4 - as a single-quoted number) True\n"; } else { print "\t \$var4 ($var4 - as a single-quoted number) False\n"; } print "\t \$var4 ($var4 - as a single-quoted number) has length of " +. length($var4) . " and ASCII value of " .ord($var4). "\n"; my $var5 = '1'; if ( $var5 ) { print "\$var5 ($var5 in single quotes) True\n"; } else { print "\$var5 ($var5 in single quotes) False\n"; } my $var6 = "1"; if ( $var6 ) { print "\$var6 ($var6 in double quotes) True\n"; } else { print "\$var6 ($var6 in double quotes) False\n"; } my $var7 = 1; if ( $var7 ) { print "\$var7 ($var7 - as an unquoted number) True\n"; } else { print "$var7 ($var7 - as an unquoted number) False\n"; }

    and that produces this output:

    $var (0) False $var (undef) False $var1 ('') False $var2 ("") False $var3 (0 - as a single-quoted number) False $var4 (0 - as a double-quoted number) False $var4 (0 - as an unquoted number) True $var4 (0 - as a single-quoted number) True $var4 (0 - as a single-quoted number) has length of 1 and AS +CII value of 48 $var5 (1 in single quotes) True $var6 (1 in double quotes) True $var7 (1 - as an unquoted number) True

    You'll also note an (imperfect) effort to do the quoting for output in the same manner each time; that kind of consistency will also help make your code more understandable... and maintainable.

    But most inportant -- make sure you grok davidos reply; hold it close until it's second nature. That will save more important problems, later.

Re: What is the correct definition of False and Null in Perl?
by Anonymous Monk on Oct 08, 2011 at 10:22 UTC