Programmers can alter the precedence and associativity rules by placing parentheses in expressions. A parenthesized part of an expression has precedence over its adjacent unparenthesized parts. For example, although multiplication has precedence over addition, in the expression
(A B) * C
the addition will be evaluated first. Mathematically, this is perfectly natural. In this expression, the first operand of the multiplication operator is not available until the addition in the parenthesized subexpression is evaluated.
Languages that allow parentheses in arithmetic expressions could dispense with all precedence rules and simply associate all operators left to right or right to left. The programmer would specify the desired order of evaluation with parentheses. This approach would be simple because neither the author nor the readers of programs would need to remember any precedence or associativity rules. The disadvantage of this scheme is that it makes writing expressions more tedious, and it also seriously compromises the readability of the code. Yet this was the choice made by Ken Iverson, the designer of APL.
Recall that Ruby is a pure object-oriented language, which means, among other things, that every data value, including literals, is an object. Ruby supports the collection of arithmetic and logic operations that are included in the C-based languages. What sets Ruby apart from the C-based languages in the area of expressions is that all of the arithmetic, relational, and assignment operators, as well as array indexing, shifts, and bitwise logic operators, are implemented as methods. For example, the expression a b is a call to the method of the object referenced by a, passing the object referenced by b as a parameter.
One interesting result of the implementation of operators as methods is that they can be overridden by application programs. Therefore, these operators can be redefined. While it is often not useful to redefine operators for predefined types, to define predefined operators for user-defined types, which can be done with operator overloading in some languages.
Expressions in LISP
As is the case with Ruby, all arithmetic and logic operations in LISP are performed by subprograms. But in LISP, the subprograms must be explicitly called. For example, to specify the C expression a b * c in LISP, one must write the following expression:
( a (* b c))
In this expression, and * are the names of functions.
if-then-else statements can be used to perform a conditional expression assignment. For example, consider
if (count == 0)
average = 0;
average = sum / count;
In the C-based languages, this code can be specified more conveniently in an assignment statement using a conditional expression, which has the form
expression_1 ? expression_2 : expression_3
where expression_1 is interpreted as a Boolean expression. If expression_1 evaluates to true, the value of the whole expression is the value of expression_2;
otherwise, it is the value of expression_3. For example, the effect of the example if-then-else can be achieved with the following assignment statement, using
a conditional expression:
average = (count == 0) ? 0 : sum / count;