Front page | perl.perl5.porters | Postings from June 2003

## perlbool.pod rev.2

From:
Dan Kogai
Date:
June 30, 2003 04:35
Subject:
perlbool.pod rev.2
Message ID:
D93B74F4-AAEE-11D7-9F5D-000393AE4244@dan.co.jp
```Autrijus and Rafael,

Here it is, the 2nd rev.

"0 but Dan the Perl5 Porter"

perlbool - semantics of boolean operations and conversions in Perl

\$f = "0";          # false by definition
\$f = "";           # false by definition
\$f = 0;            # false by definition
\$f = 0.00;         # false because 0.00 == 0.
\$t =  \\$a;         # always true
\$f = undef         # always false
\$t = 1;            # true
\$f = 10 - 10;      # equals 0 so false
\$t = "0.00";       # true! see below
\$f = "0.00" + 0    # numerically 0 so false
\$t = "0 but true"; # true, though 0 in numeric conversion
@f = ();           # scalar @f is 0 so false
@t = (0);          # scalar @t is 1 so true!
%h = (0 => undef); # scalar %h is nonzero so %h is true
delete \$h{0};      # scalar %h is now 0 so %h is false

This document describes how Perl distinguish between true and false.

To perl, only the following values are false and everything else is
true.

=over

=item *

string C<""> (null string) and C<"0">

=item *

number C<0>

=back

Consider the above as axioms and any other "theorems" are reduced to
the axioms above.

=over

=item *

All references are true since it is neither string nor number.
This is unlike C which has null pointers.

=item *

When boolean values are needed, perl does not do any type coercion.
It just checks to see if the value matches  C<"">, C<"0">, or C<0>.

That is why C<"0.00"> is true while C<"0.00"+0> is false.  Though
"0.00" is numerically 0, it is "0.00" until numerical value is needed,
which is neither "" nor "0".

=back

Unlike C which has null pointers, perl's reference is always true
because in string context it would be something like
C<SCALAR(0x8134654)> in string and C<135480916> in numerical context
(because C<0x8134654> is hexadecimal for C<135480916>).

In practice perl does not waste time coercing references to strings
just to see if it is true because perl already knows this theorem

C<undef()> is always false because it would evaluate to C<""> in
string context and C<0> in numerical context.

Like references, perl already knows C<undef()> is always false so
no coercion takes place.

=head2 Boolean values of arrays and hashes

For boolean values of arrays and hashes, perl just uses C<scalar()>
thereof.  In other words, boolean values of arrays and hashes are
false when and only when they are empty.

C<@a = ()> is false but C<@a = (0)> and C<@a = ("")> are both true.

Like C, many functions in perl returns 0 on failures so you can write
C<if (func()){....}> instead of C<if (function() == 0){....}>.  But
sometimes you want 0 to be a valid, successful numerical value.  For
such cases, use C<0 but true> on success and C<undef> on failure.

As a matter of fact, perl's built-in C<ioctl()>, C<semget()> and
C<sysseek()> uses this semantics so you can safely say

\$offset = sysseek(\$fh 0, SEEK_CUR)
or die "sysseek failed: \$!";

defined(\$offset = sysseek(\$fh 0, SEEK_CUR))
or die "sysseek failed: \$!";

Of couse C<0 but true> is not the only valid solution.  C<0e0>, C<0.0>
or even C<0.> is okay (L<Net::POP3>, for instance, uses C<0E0>).

However, it is good to remember that C<0 but true> is the one used by
perl built-in functions.  It is also the most self-explanatory.

=head1 Boolean Context vs. Boolean Value

Though perl does not have explicit boolean value like C<t> or C<nil> in
LISP and ruby, perl does have boolean context.

\$a;         # void context
\$a+1        # scalar context
push @a, \$a # array context
if (\$a)     # boolean context

What is interesting is that perl's comparison operators return values
in scalar context; C<1> for true and C<undef> for false.

not(\$a)+1;  # 1 if \$a is true and 2 otherwise.

The lack of boolean value is no problem since boolean context exists.
See L</Overload> for such cases that boolean context does differ from
scalar context.

Because perl does have boolean context, you can use L<overload> to
give your object a different idea from perl on what is true and false.
The following example make a scalar which is always false.

package NeverTrue;
'bool'   => sub { 0 },
'""'     => sub { my \$self = shift; \$\$self },
'0+'     => sub { my \$self = shift; \$\$self },
fallback => 1;
sub new {
my \$class = ref \$_[0] ? ref shift : shift;
my \$value = shift;
return bless \\$value => \$class;
};

package main;
my \$t = NeverTrue->new("1 but false");
printf "Boolean: %s\n", \$t ? 't' : 'f';
printf "String:  %s\n", \$t . "";
printf "Number:  %d\n", \$t + 0;

0th draft by Dan Kogai <dankogai@dan.co.jp>

Revision by Tassilo von Parseval <tassilo.parseval@post.rwth-aachen.de>,
Autrijus Tang <autrijus@autrijus.org>,
Rafael Garcia-Suarez <raphel.garcia-suarez@hexaflux.com>,
and Perl5 Porters <perl5-porters@perl.org>