Sunday, 1 February 2015

Comparing Booleans in Perl

Boolean equality can be checked in Perl with

!($x xor $y)

or with

!$x == !$y

And the winner is...

Strings, integers, floating point numbers and Booleans all have a single type in Perl - that's the scalar. Given a variable $x we can treat it as a Boolean by writing something like

if ($x) {
  print 'x is true';
else {
  print 'x is false';

It will print 'x is false' if $x is one of:
  • 0 - the number zero;
  • '' - an empty string;
  • '0' - the string consisting of the zero digit; or
  • undef - a variable which has no value assigned to it.
For any other value 'x is true' will be printed.

Having such an accommodating Boolean evaluation saves us keystrokes but can sometimes be a bit of a mind-bender when trying to compare variables as Booleans. For example, suppose $x = 'true' and $y = '2b or !2b?', then both of these scalars would be true as Booleans, but both ($x == $y) and ($x eq $y) would evaluate as false.

So how do we compare them as Booleans? The two approaches above are quite different.

The naysayers: !$x == !$y

Given a scalar $x, evaluating !$x makes it clear it should be regarded as a Boolean and the value returned by ! will be Perl's default representation of its Boolean opposite: 1 for true or the empty string for false.

Exclusive: !($x xor $y)

Noting that xor is short for 'exclusive or' which is to say that either side is true, but not both. Once again, because it's a logical operator, it returns 1 or the empty string. This works because

NOT( x XOR y ) ⇔ NOT( ( x OR y ) AND NOT ( x AND y ) )
               ⇔ NOT( x OR y ) OR (x AND y)
               ⇔ x = y # as Booleans


Running this on my old laptop with Perl v5.14.2 I found the "exclusive" approach to be 2-3% faster. I'd like to know how the competition pans out on other people's systems. See my code here:

No comments:

Post a Comment