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

Inspired by some goings-on yesterday in the CB I realized that a discussion of the many uses of the && and || operators might be in order. Camel (Programming Perl, O'Reilly) calls them "C-style Logical (Short Circuit) Operators." So can something so blatently borrowed from C be considered an integral Perl idiom? Definately. Here's why, and why they're an important part of the Perl toolbelt.

C-style?
First, to set the record straight, though they are "C-style operators", they are not carbon copies of their C cousins. perlop states, "The || and && operators differ from C's in that, rather than returning 0 or 1, they return the last value evaluated." And therein lies one of the important powers of these operators. They are often referred to as being "C-style" because C is a well known language that helped to establish the custom of short-circuit behavior for these operators (and that's the last time I'll mention C... for now).

Why "Short Circuit?"

Camel II tells us that the term "Short-Circuit" refers to the fact that they "determine the truth of the statement by evaluating the fewest number of operands possible." So essentially these operators stop the chain of evaluation of an expression as early as possible. That is another key to their value.

Why "Logical?"
Logical just means that the && and || operators impose some logic on the expression they're a part of. And logic implies decision making, or conditional flow control. That's the final key to the power these operators wield.

What do they do?

--------------------------------------------------------- $this && $that | If $this is true, return $that, $this and $that | else return $this. -----------------+--------------------------------------- $this || $that | If $this is true, return $this, $this or $that | else return $that. ---------------------------------------------------------

The above table also lists && and ||'s siblings: 'and' and 'or'. The latter two work the same as the former two, except with a lower precedence, so as to reduce the need for parenthesis. More on that later.

A closer look at && logic and short-circuiting:
If you're already comfortable with how they work, skip the next two code segments and just resume reading with the discussion of actual Perl idioms.

Here is a set of simple examples that illustrate what these operators are doing:

  • && with both expressions true.
    my ($first, $second) = ( 1, 1 ); print "Truth\n" if $first++ && $second++; print "First: $first\nSecond: $second\n"; __OUTPUT__ Truth First: 2 Second: 2
  • && with first expression true and second false.
    my ($first, $second) = ( 1, 0 ); print "Truth\n" if $first++ && $second++; print "First: $first\nSecond: $second\n"; __OUTPUT__ First: 2 Second: 1 # Note: Both are evaluated because the first one is # true. But "Truth" isn't printed, because only one # of the two expressions evaluated "true".
  • && with first expression false and 2nd true.
    my ($first, $second) = ( 0, 1 ); print "Truth\n" if $first++ && $second++; print "First: $first\nSecond: $second\n"; __OUTPUT__ First: 1 Second: 1 # $second didn't get incremented because the # evaluation stopped when $first evaluated false.
  • && with both expressions false.
    my ($first, $second) = ( 0, 0 ); print "Truth\n" if $first++ && $second++; print "First: $first\nSecond: $second\n"; __Output__ First: 1 Second: 0 # $first was evaluated for truth. It was false, # so $second didn't get evaluated.

In the above example you can see short-circuiting and logic both in action. "Truth" is only printed in the first example, because that is the only example where $this and $that were true at the time of evaluation. The rest of the examples showed how short-circuiting affected whether or not the second expression ($that) ever got evaluated. You can see if it gets evaluated by virtue of the ++ operator: If it got incremented, it got evaluated.

||'s version of logic and short-circuiting: The following examples express in fairly simple terms what || does:

  • || with both expressions true.
    my ($first, $second) = ( 1, 1 ); print "Truth\n" if $first++ || $second++; print "First: $first\nSecond: $second\n"; __OUTPUT__ Truth First: 2 Second: 1 # Since $first is true, no need to evaluate $second; # we already know that the 'or' expression is true.
  • || with first expressions true, second false.
    my ($first, $second) = ( 1, 0 ); print "Truth\n" if $first++ || $second++; print "First: $first\nSecond: $second\n"; __OUTPUT__ Truth First: 2 Second: 0 # Again, $second is never evaluated because $first # is true, and that's good enough for ||.
  • || with first expression false, second true.
    my ($first, $second) = ( 0, 1 ); print "Truth\n" if $first++ || $second++; print "First: $first\nSecond: $second\n"; __OUTPUT__ Truth First: 1 Second: 2 # Both sides got evaluated because since $first was # false it was necessary to evaluate $second to # determine if truth exists (it does).
  • || with both expressions false.
    my ($first, $second) = ( 0, 0 ); print "Truth\n" if $first++ || $second++; print "First: $first\nSecond: $second\n"; __OUTPUT__ First: 1 Second: 1 # There is no truth. Both expressions were # evaluated to find it.

So to use a catchy phrase, && "falls through" if the first expression is true, and returns truth if both are true.
|| "falls through" if the first expression is false, and returns truth if either expression is true.
And as mentioned before "returns truth" means returns the last expression evaluated.

So what about the idioms?
There are a lot of them. Here are a few to whet your apetite:

open( FILE, "<filename" ) || die "Cannot open filename: $!\n"; # Open the file. If the open fails (and thus evaluates # false) fall through to the second half: die.

That's one you see all over the place. In a moment I'll mention why "open(...) or die ..." is better than "open(...) || die ...". The great thing about these operators is that they "read well". They do exactly what they say: "open or die", for example.

Here's another common idiom that uses && to provide a C-like "switch" statement (Ok, now I promise not to mention C anymore):

local $_ = 'xyz'; SWITCH: { /^abc/ && do { $abc = 1; last SWITCH; }; /^def/ && do { $def = 1; last SWITCH; }; /^xyz/ && do { $xyz = 1; last SWITCH; }; $default = 1; }
(Credit to perlsyn for the bulk of that example.) The preceeding example may look a little funky. How does it make sense to say "if this and do that"? Remember that "do" returns the value of the last expression evaluated inside it. So basically the preceeding example says "If this and that." But the truthfulness of the second expression isn't important anyway. What we're doing is evaluating the truthfulness of the first expression to determine whether or not to fall through to evaluate the second expression. So in the preceeding example, "$_ =~ /^xyz/" is true, so everything inside the do{ ... } expression gets evaluated, or executed. This is one of the ways to implement switch (hashtables can be more efficient though). Now you know one reason why Perl 5 doesn't have a switch statement (though there is a Switch module if you really need switch, and Perl 6 will have it).

You are free to chain these operators together as well. You could, for example, say:

if ( $this && $that && $other ) { print "Truth\n"; }

or even...

my $client = $ENV{USER_HOST} || $ENV{USER_ADDR} || "UNKNOWN";

And now for the super-cool idiom that reminded me that I wanted to write this node in the first place:

my @sorted = sort { uc($a) cmp uc($b) || $a cmp $b } @unsorted;

What is going on here? Remember that "cmp" and "<=>" evaluate to "zero" (false) if the left hand side and the right hand side are equal, and "false" will make '||' fall through to the next level. We're sorting a list case-insensitively, but if there is both an upper-case and lower-case string that, when evaluated case-insensitively, would evaluate to being equal, the || will fall through to the second expression, which evaluates case-SENsitively. In other words: (qw/b c a C D E e f/) would sort as: (qw/a b C c D E e f/) (assuming you're on an ASCII system).

This idiom can be wielded in an even more powerful way. Consider, for example, a multi-dimensional entity where you want to sort complexly (is that a word?):

my @list = ( { 'Name' => "Pete", 'Age' => 32 }, { 'Name' => "Pete", 'Age' => 55 } ); my @sorted = sort { $a->{'Name'} cmp $b->{'Name'} || $a->{'Age' } <=> $b->{'Age' } } @list;

In that example, you're going to sort by name first, and whenever two names are equal, fall through to subsort by age.

Precedence
There are situations where && and || may be of too-high precedence, thus necessitating the use of parenthesis. The "open or die" example provided above is one of those situations. But && and || have younger siblings with lower precedence. The "open or die" example could be written another way:

open ( FILE, "<filename" ) || die ..... # You already saw this one. open FILE, "<filename" or die .... # Notice how the much lower # precedence of "or" makes the parenthesis unnecessary in # this case.

Just think of "and" and "or" as being the same as && and ||, but so low on the precedence chart that parenthesis are usually unnecessary to keep the things on the left or on the right properly grouped. It is almost always considered better to use "or" instead of "||" when you work with open.

Ok, that's all I have to say. Thanks for staying awake through this longwinded node!

I hope some readers find this discussion helpful.

Update: My thanks to hardburn, Abigail-II, tye, Enlil, diotalevi, demerphq and a few others for providing comments that helped me to refine this node a bit.

Additional Reading:
Programming Perl O'Reilly: Chapter on Operators.
perlop from the Perl POD.
perlsyn from the Perl POD.
perlfunc: sections on sort and open.
perlopentut: tutorial on opening files.


Dave


"If I had my life to live over again, I'd be a plumber." -- Albert Einstein