Please note that this tutorial is undergoing revision and expansion, so the comments that follow it may apply to an earlier version. This version is dated: 5Dec2006
If, like me, you don't come from a compsci background, then precedenceawareness of operators probably only goes as far as knowing that 2+3*4 means 2+(3*4), and that if you want (2+3)*4, then you'd better damn well say so.
Beyond that, 51+2 might have you scratching your head  which has precedence  the '' or the '+'? The answer is 'whichever comes first'  they have equal precedence but left associativity, so 51+2 is (51)+2, but 5+12 is (5+1)2 (although you'll have fun proving that last one).
... and it's worth mentioning for the compsci challenged that leftassociativity means "for a sequence of operators of equal precedence, give the leftmost operator the precedence". Rightassociativity means the reverse. For example, ** (the 'tothepowerof' operator) has rightassociativity, so 2**3**4 is 2**(2**3), not (2**2)**3.
So far, it's all pretty straightforward. Whether or not you know what the rules for precedence are for the basic maths operators, you are aware that they exist and need to exist, and, if in doubt, or if you just want to make things clearer for yourself or the codemaintainer, you can always use brackets to make the order of operations explicit.
So far, so good  that is until we get to the numericequality test, '==' and the assignment operator, '='.
The first thing to note (or at least remember) about these is that don't really have anything in common with each other. Nor do either have any strict equivalent in maths (unlike, say, '*' and '/', etc.).
It may be tempting to think otherwise, since $x = 2*4 (Perl) seems to behave a bit like X = 2 x 4 (maths). However, since we can use '=' to assign just about anything to $x, including "hello world", it really doesn't have anything to do with numbers.
In Perl, '==', and its eviltwin, '!=', are perhaps a bit closer to the mathsclass meaning of '=', since all are associated with the numeric equality of the calculations on either side  however, in maths if the two sides don't match the operator, then you've probably made a mistake, whereas in Perl if the two sides don't match the operator, then you've just performed a valid test.
Nevertheless, the notion of precedence for these operators is somewhat confusing  if precedence is important, does that mean that we have to write ($x+$y) == (12/3) to avoid something like $x+($y == 12/3) happening? And what would that mean anyway?
By and large, you don't need to worry. Both '=' and '==' have such low precedence that they will almost always behave as you expect (and certainly as far as any mathsbased functions go), without any need for parenthesis.
However, there are some traps when we start combining '==' and '=' with the various logical operators, such as 'and' and 'or', and their alternatives, '&&' and '¦¦', as these do have lower precedence.
For example, (5 or 2 == 12) doesn't mean "does 5 or 2 equal 12?" (which would be false), instead it translates to 5 or (2 == 12), or "if 5 is true or if 2 equals 12" (which is true  5 is a 'true' value).
To add to the confusion, '&&' and '¦¦' have a higher precedence than '=', whereas 'and' and 'or' have a lower precedence. This means that $x = 4==5 ¦¦ 5==5 has quite a different meaning than $x = 4==5 or 5==5  the first will set $x to 1 ('true') if either 4 or 5 is equal to 5, and will set $x to false if they are not. The second version will set $x to true or false purely on the basis of whether 4 is equal to 5 (and will go on to check whether 5 is equal to 5 if it fails to set $x to a value).
Below is a short table that will hopefully make all of this a little clearer.
Function  Meaning  $x is now.. 
$x = 5 == 6 or 5 == 5  ($x = (5 == 6)) or ($x = (5 == 5))  FALSE 
$x = (5 == 6 or 5 == 5)  $x = ((5 == 6) or (5 == 5))  TRUE 
$x = 5 == 6 ¦¦ 5 == 5  $x = ((5 == 6) ¦¦ (5 == 5))  TRUE 
($x = 5 == 6) ¦¦ 5 == 5  ($x = 5 == 6) ¦¦ 5 == 5  FALSE 
$x = 5 ¦¦ 6 == 6  $x = (5 ¦¦ (6 == 6))  5 
$x = (5 ¦¦ 6) == 6  $x = ((5 ¦¦ 6) == 6)  TRUE 
$x = 5 or 6 == 6  ($x = 5) ¦¦ ($x = (6 == 6))  5 
$x = 1 == 2 && 3  $x = (1 == 2) && $x = 3  3 
$x = 1 == 2 ¦¦ 3  $x = (1 == 2) ¦¦ $x = 3  FALSE 
The real lesson here is that when you start mixing '==' or '=' with any logical operators, get into the habit of using parenthesis... and just to rub that in, let's take a look at another logical operator, the slightly obscure, but extremely useful '?:'  and a particular trap you can fall into due to making unwarranted assumptions about the behavior of '='.
The '?:' operator is probably the leastknown operator, so let's take a quick look at what it does.
The basic syntax is: <test>?<value to return if test is true>:<value to return if test is false>
Now, the "?:" construct is very useful  basically, it means that we can replace the following code:
if($x){ $y=1; } else{ $y=0; }
with:
$y = $x ? 1 : 0;
Which is all well and good  unless you make the mistake of writing:
$x ? $y=1 : $y=0;
If you run the above code, you will find that, whatever value you assign to $x, you are always told that, apparently, $x was false (i.e. $y is set to 0).
So how did that happen, why was it confusing (IMHO), and what can you do about it?
Well, to illustrate what happened, let's write an alternative version that doesn't exhibit the problem, but looks pretty much identical (using a regex substitution instead of '='):
$x ? $y=1 : $y=~s/.*/0/;
This time, we get the result we expect. So what happened in the bad version that didn't happen here? Well the first thing to notice in the operatorprecedence table is that '=~' has a higher precedence than '?:', but '=' has a lower precedence. So what? All that means, presumably, is that we decide on the truth or falsehood of our initial condition before we assign any value to $y (which sounds like a good thing).
Well... no. What precedence conceptually means in this context is "where is the boundary of our false expression?" and the answer is "it's when we hit an operator with a lower precedence than '?:'"
So $x ? $y=1 : $y=0 can be expressed as ($x ? $y=1 : $y)=0  which, if $x is false, leads to ($y)=0 (correct), but if $x is true, leads to ($y=1)=0 (uhoh  we did set $y to 1, but then immediately reset it to 0).
Now, when we replace a false expression such as $y=0 with $y=~s/.*/0/, the higher precedence of '=~' means that Perl evaluates this as:
$x ? $y=1 : ($y=~s/.*/0/)
which is probably what we (the compsci challenged) expected in the first example.
Bottom line, '?:' can benefit from parenthesis just as much as (2+3)*5  here is the bad code made good:
$x ? $y=1 : ($y=0);
As a small sidenote, really we ought to be writing $x ? ($y=1) : ($y=0);, but Perl 'knows' that the function between '?' and ':' must be our 'true' function and is kind enough to add the virtual parenthesis for us...
...and, as noted before, we can avoid the need for parenthesis, and save a few keystrokes, by writing:
$y = $x ? 1 : 0;
... which is really what we should have done in the first place  there is an Meditation discussing the use of '?:' at ?: = Obfuscation?.
This is not meant to be an exhaustive look at precedence and operators  I haven't mentioned the bitwise operators for example. However, I hope I've covered the issues likely to fox the compsci challenged (basically, if you're using bitwise operators, I assume you know what you're doing).
Also, I'm halftempted (well, 25% tempted) to replace this tutorial with just the one sentence "USE LOTS OF PARENTHESIS"  it's certainly the bottom line. They will make your code more readable, and you will avoid most of the traps associated with precedence.
That said, don't go over the top:
$x = ((((((1 * 2) * 3) * (4 ** 2)) * 5) * 6) * 7)
is not really helping anyone....


Replies are listed 'Best First'.  

Re: Precedence for Idiots
by BrowserUk (Pope) on Dec 01, 2006 at 14:37 UTC  
Re: Precedence for Idiots
by Tanktalus (Canon) on Dec 01, 2006 at 15:22 UTC  
by jdporter (Canon) on Dec 01, 2006 at 15:40 UTC  
by Melly (Hermit) on Dec 01, 2006 at 16:10 UTC  
Re: Precedence for Idiots
by virtualsue (Vicar) on Dec 01, 2006 at 16:16 UTC  
by Melly (Hermit) on Dec 01, 2006 at 16:26 UTC  
Re: Precedence for Idiots
by mreece (Friar) on Dec 01, 2006 at 15:28 UTC  
Re: Precedence for Idiots
by calin (Deacon) on Dec 04, 2006 at 21:59 UTC  
by Melly (Hermit) on Dec 04, 2006 at 23:18 UTC  
Re: Precedence for Idiots
by throop (Chaplain) on Dec 01, 2006 at 21:52 UTC 