http://qs321.pair.com?node_id=133554

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);
prints
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.

Objects

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;
prints:
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!