Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw

What is truth? (Curiosity corner)

by robin (Chaplain)
on Dec 20, 2001 at 22:28 UTC ( #133554=perlmeditation: print w/replies, xml ) Need Help??

In my last meditation I talked about Perl's notion of truth, and mentioned some subtleties. I thought it would be interesting to go into a bit more detail, and describe the complications introduced by overloaded objects.

Update: I've added a <readmore> tag, as suggested by a reaped anonymonk. Sorry if I've violated protocol - I'm new here; feel free to offer friendly advice :-)

The basics

A simple scalar is just an ordinary number or string. There's a special scalar, undef, which is the default value assumed by variables if you don't give them any other value.

Every scalar, simple or otherwise, has a numeric value, a string value and a truth value. You can check them like this:

sub explain { my $val = shift; print "Numeric value = ", 0+$val, "\n"; print "String value = \"$val\"\n"; print "Truth value = ", $val ? "true\n" : "false\n"; }
Here are some examples:
# explain("23skidoo"); Numeric value = 23 String value = "23skidoo" Truth value = true # explain(1_2_3); Numeric value = 123 String value = "123" Truth value = true # explain("1_2_3"); Numeric value = 1 String value = "1_2_3" Truth value = true # explain("00"); Numeric value = 0 String value = "00" Truth value = true # explain("0"); Numeric value = 0 String value = "0" Truth value = false # explain(undef); Numeric value = 0 String value = "" Truth value = false
The rule for determining the boolean value is very simple: if the string value is "" or "0" then it's false; otherwise it's true. Notice that the numeric value is actually irrelevant to truth, except insofar as it can determine the string value. Traditionally in Perl, the string "0 but true" is used as a value which is true, but numerically zero. In fact, that tradition is subtly enshrined in the interpreter: ordinarily, you get a warning when you use a string which contains non-digits as if it were a number:
[robin@robin robin]$ perl -wle 'print 0+"23skidoo"' Argument "23skidoo" isn't numeric in addition (+) at -e line 1. 23
But the string "0 but true" is exempt from the warning:
[robin@robin bits &amp; pieces]$ perl -wle 'print 23+"0 but true"' 23

References and typeglobs

Not all scalars are simple. Some are references. Let's try one:
# explain([1,2,3]); Numeric value = 25616 String value = "ARRAY(0x6410)" Truth value = true
The numeric value is just the memory address used to store the target of the reference. (25616 (base 10) is equal to 6410 (base 16).) That's handy, because it means you can compare two references with $ref1 == $ref2 to find out if they both refer to the same thing.

Some references are blessed, of course. Objects. We'll look at those in the next section. But there's another kind of special scalar - the typeglob. If you did much Perl programming back in the days of Perl 4 you'll certainly remember typeglobs, because they behave like references in some ways and Perl 4 didn't have proper references.

my $foo = *bar; our $bar = "hello\n"; our @bar = ("Hello again!\n"); print $$foo, @$foo; explain($foo);
hello Hello again! Numeric value = 0 String value = "*main::bar" Truth value = true
So the string value of a glob is just the fully-qualified name of the variable(s) it refers to, preceded by a star.


An object is just a blessed reference:
# explain(bless {}, "SomePackage"); Numeric value = 25616 String value = "SomePackage=HASH(0x6410)" Truth value = true
That's just like an ordinary reference, except that the name of the package it's blessed into is added to the beginning of the string value.

So far, the golden rule for truth has been adhered to strictly. Even the most esoteric special scalars are false if they have a string value of "" or "0", and otherwise they're true. But it gets more complicated than that. You can use overloading to change the default behaviour of an object.

explain(bless {}, "SomePackage"); package SomePackage; use overload '""' => sub {'string value'}; use overload '0+' => sub {23}; use overload 'bool' => sub {""}; use overload fallback => 1;
Numeric value = 23 String value = "string value" Truth value = false
So you see that each of the three type conversions can be specified separately, and they don't have to be consistent with one another. That's reminiscent of the special variable $!, which gives an error number when used numerically and an error message when used as a string.

You don't have to specify all three. Perl will work out the unspecified conversions based on the conversions that you do specify. Suppose that we delete the '0+' and bool lines from the code above:

Numeric value = 0 String value = "string value" Truth value = true
That's what you ought to expect: Perl is making the same conversions that it would for an ordinary string. Okay, so suppose we specify the string value and the numeric value. What would you expect the truth value to be in this example:
explain(bless {}, "SomePackage"); package SomePackage; use overload '""' => sub {''}; use overload '0+' => sub {23}; use overload fallback => 1;
The answer is surprising. The golden rule is broken!
Numeric value = 23 String value = "" Truth value = true
Even though the string value is "", Perl still considers it to be true! In fact, the numeric value (if it exists) is always used to determine truth when overloading is in effect. (Unless of course an explicit truth value is supplied as well using the 'bool' overload.) This is very strange, and there doesn't appear to be any good reason for it. Unfortunately if we fixed it then existing code would break, so we're probably stuck with it, at least until Perl 6.

Actually, it's even weirder than it looks. What about this?

explain(bless {}, "SomePackage"); package SomePackage; use overload '""' => sub { '' }; use overload '0+' => sub {'00'}; use overload fallback => 1;
Can you predict the truth value? The thing is, the golden rule is being used here, but in a very odd way. The numeric value has a string value of "00", and so it's false!

The truth value is determined by the string value of the numeric value. Wondrous strange!

Replies are listed 'Best First'.
Re: What is truth? (Curiosity corner)
by Anonymous Monk on Dec 21, 2001 at 01:17 UTC
    What about "0E0" for zero-but-true? Doesn't it work the same way?
    perl -wle 'print 23+"0E0" if "0E0"' 23
      Yeah, it does indeed. I'm not quite sure why "0 but true" is often preferred. Maybe because it's more explicit about its intention?
        "0E0" is used by the DBI (and DBD's) for eg. $sth->execute when the SQL-statement processed 0 rows but did not error.

        This allows constructions like my $rows=$sth->execute or die "SQL error" ( Of course this would be expressed better using $dbh->{RaiseError} = 1).

        The relevant part of the DBI documentation states:

        For a non-`SELECT' statement, `execute' returns the number of rows affected, if known. If no rows were affected, then `execute' returns "`0E0'", which Perl will treat as 0 but will regard as true. Note that it is not an error for no rows to be affected by a statement. If the number of rows affected is not known, then `execute' returns -1.

Re: What is truth? (Curiosity corner)
by sparkyichi (Deacon) on Dec 21, 2001 at 22:10 UTC
    I learned alot from your post Robin. Think that it might be best placed in the Tutorials section. People new to Perl may be able to glean much from your post and they may have more of a chance to see it if it is placed there.

      Yes, you're probably right.

      I didn't set out to write a tutorial, but I agree that it's ended up looking a lot like one. :-)

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://133554]
Approved by root
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (7)
As of 2023-11-28 12:54 GMT
Find Nodes?
    Voting Booth?

    No recent polls found