Page 2 of 3
Functions and operators
Put simply you can say that an operator is simply a function that has a priority associated with it.
For example, rather than the usual arithmetic operators we could easily get by with the functions ADD(a,b), SUB(a,b), MULT(a,b) and DIV(a,b) as long as they had the same priorities assigned to them.
The question of how to write operator expressions neatly has exercised the minds of many a mathematician. The usual notation that suits dyadic operators, i.e. A+B is called infix notation but it doesn't generalise to n-adic operators.
A better, but less familiar, notation is reverse Polish where the operator is written after its operands. For example, AB+ is reverse Polish for A+B. The advantage of reverse Polish is that it does generalise to n-adic operators.
For example, ABC@ is a reverse Polish expression using the triadic operator that finds the maximum of A,B and C.
Reverse Polish has another advantage in that operator priorities can be represented by the order that they occur.
For example, AB+C* is clearly (A+B)*C because the multiplication cannot be evaluated until the addition is evaluated to provide the second operand for the multiplication.
Because an operator can look like a function it is possible to confuse the two. For example, in Ada abs, i.e. taking the absolute value of a quantity, is an operator but in Pacal and most other languages it is a function. If you don't notice this subtle difference you could end up writing expressions in Ada or Pascal that don't work as you expect.
As well as not agreeing about whether something is an operator or a function languages don't always agree about the assignment of priorities and if you switch languages this can be a cause of serious and difficult to find bugs.
For example, Fortran and BASIC give the exponentiation operator ^ the highest precedence but most spreadsheets give it second place to the unitary minus -.
It isn't even always reasonable to stick to a simple precedence rule in all cases. For example, in many languages the exponentiation operation has the highest precedence of all operators and in general this is reasonable but consider
using the strict precedence this should be
i.e. -16 but this clearly isn't what the programmer intended. To put things right many languages alter the priority of exponentiation when it is immediately followed by negation. That is 4^-2 is evaluated as 4 raised to the power of -2 (i.e. 1/16).
Operators and expressions are powerful and compact ways of writing programs and many languages cannot resist the temptation to use them for nearly everything.
The most often quoted example of an operator based language is APL but surprisingly it doesn't use an operator precedence at all and simply evaluates everything left to right!
Operators in C
In my opinion the operator king of modern languages is C and many of the languages that are based on it.
C has a range of operators that needs 16 levels of precedence to control! This bewildering array of operators is one of the reasons why C is intimating to the beginner and can look cryptic.
Once you start to extend the range of operators that a language has then you have to worry about associativity as well as precedence.
Associativity is simply the order that operators of the same priority will be evaluated. If you restrict your attention to simple arithmetic operators then the associativity isn't a problem because (A+B)+C is the same as A+(B+C).
However when you move on to consider more general operators it does matter. For example, in C and many other languages (C# for example) the right shift operator A>>B shifts A right by B bits and
which means shift A right by B+C isn't the same as
shift A right by the result of the right shift of B by C bits.
To make the result of such operations unambiguous C defines each operator as associating left to right or right to left. The >> operator associates left to right because this means that A>>B>>C is (A>>B)>>C and this is the same as A>>(B+C).