|Perl: the Markov chain saw|
What is truth? (Curiosity corner)by robin (Chaplain)
|on Dec 20, 2001 at 22:28 UTC||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 basicsA 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:
Here are some examples:
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:
But the string "0 but true" is exempt from the warning:
References and typeglobsNot all scalars are simple. Some are references. Let's try one:
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.
So the string value of a glob is just the fully-qualified name of the variable(s) it refers to, preceded by a star.
ObjectsAn object is just a blessed reference:
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.
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:
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:
The answer is surprising. The golden rule is broken!
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?
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!