Robert's Perl Tutorial

http://www.sthomas.net/roberts-perl-tutorial.htm


Precedence: What comes First

To understand the difference between the two we need to talk about precedence. Precedence means priority, order, importance. A good example is:

perl -e"print 2+8

which we know equals 10. But if we add:

perl -e"print 2+8/2

Now, will this be 2+8 == 10, divided by 2 == 5? Or maybe 8/2 == 4, plus 2 == 6?

Precedence is about what is done first. In the example above, you can see that the division is done first, then the addition. Therefore, division has a higher precedence that addition.

You can force the issue with parens:

perl -e"print ((2+8)/2)

which forces Perl, kicking and screaming, to evaluate 2+8 then divide the result by 2.

So what has this to do with logical operators? Well, the main difference between or and || is precedence.

In the example below, we attempt to assign two variables to non-existent elements of an array. This will fail:

@list=qw(a b c);

$name1 =  $list[4] or "1-Unknown";

$name2 =  $list[4] || "2-Unknown";

print "Name1 is $name1, Name2 is $name2\n";

print "Name1 exists\n" if defined $name1;
print "Name2 exists\n" if defined $name2;

The output is interesting. The variable $name2 has been created, albeit with a false value. However, $name1 does not exist. The reason is all about precedence. The or operator has a lower precedence than || .

This means or looks at the entire expression on its left hand side. In this case, that is $name1 = $list[4] . If it is true, it gets done. If it is false, it is not and the right hand side is evaluated, and the left hand side is ignored as if it never existed. In the example above, once the left side is found to be false, then all the right side evaluates is "1-Unknown" which may be true but doesn't produce any output.

In the case of || , which has a higher precedence, the code immediately on the left of the operator is evaluated. In this case, that is $list[4]. This is false, so the code immediately to the right is evaluated. But, the original code on the left which was not evaluated, $name2 = is not forgotten. Therefore, the expression evaluated to $name2 = "2-Unknown".

The example below should help clarify things:

@list=qw(a b c);

$ele1 = $list[4] or print "1 Failed\n";
$ele2 = $list[4] || print "2 Failed\n";

print <<PRT;
ele1 :$ele1:

ele2 :$ele2:

PRT

The two failure codes are both printed, but for different reasons. The first is printed because we are assigning $ele1 a false value, so the result of the operation is false. Therefore, the right hand side is evaluated.

The second is printed because $list[4] itself false. Yet, as you can see, $ele2 exists. Any idea why?

The reason is that the result of print "2-Failed\n" has been assigned to $ele2. This is successful, and therefore returns 1.

Another example:

$file='not-there.txt';

open FILE, $file   || print "1: Can't open file:$!\n";

open FILE, $file   or print "2: Can't open file:$!\n";

In the first example, the error message is not printed. This is because $file is evaluating to true. However, in the second example, or looks at the entire expression, not just what is immediately to the left and takes action on the result of evaluating the entire left hand side, not just the expression immediately to its left.

You can fix things with parens:

$file='not-there.txt';

open FILE, $file   || print "1: Can't open file:$!\n";

open FILE, $file   or print "2: Can't open file:$!\n";

open (FILE, $file) || print "3: Can't open file:$!\n";

like so, but why bother when you have a perfectly good operator in or ? You could apply parens elsewhere:

@list=qw(a b c);

$name1 =  $list[4]   or "1-Unknown";

($name2 =  $list[4]) || "2-Unknown";

print "Name1 is $name1, Name2 is $name2\n";

print "Name1 exists\n" if defined $name1;
print "Name2 exists\n" if defined $name2;

Now, ($name2 = $list[4]) is evaluated as a complete expression, not just as $list[4] is evaluated as a complete expression, not just as $list[4], so we get exactly the same result as if we used or .