Chapter 7
Expressions and
Assignment
Statements
ISBN 0-321-49362-1
Chapter 7 Topics
•
•
•
•
•
•
•
•
Introduction
Arithmetic Expressions
Overloaded Operators
Type Conversions
Relational and Boolean Expressions
Short-Circuit Evaluation
Assignment Statements
Mixed-Mode Assignment
Copyright © 2007 Addison-Wesley. All rights reserved.
1-2
Introduction
• Expressions are the fundamental means of
specifying computations in a programming
language
• To understand expression evaluation, we
need to be familiar with the orders of
operator and operand evaluation
• The essence of imperative languages is the
dominant role of assignment statements.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-3
Arithmetic Expressions
• Arithmetic evaluation was one of the
motivations for the development of the first
programming languages.
• Arithmetic expressions consist of
operators, operands, parentheses, and
function calls.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-4
Arithmetic Expressions: Design Issues
• Design issues for arithmetic expressions
–
–
–
–
–
–
operator precedence rules
operator associativity rules
order of operand evaluation
operand evaluation side effects
operator overloading
mode mixing expressions
Copyright © 2007 Addison-Wesley. All rights reserved.
1-5
Arithmetic Expressions: Operators
• A unary operator has one operand
• A binary operator has two operands
• A ternary operator has three operands
Copyright © 2007 Addison-Wesley. All rights reserved.
1-6
Arithmetic Expressions: Operator
Precedence Rules
• The operator precedence rules for
expression evaluation define the order in
which “adjacent” operators of different
precedence levels are evaluated
• Typical precedence levels
–
–
–
–
–
parentheses
unary operators
** (if the language supports it)
*, /
+, -
Copyright © 2007 Addison-Wesley. All rights reserved.
1-7
Arithmetic Expressions: Operator
Precedence Rules
A few interesting notes:
•
In Java and C# the unary plus and minus operators causes an implicit
conversion of short or byte operands to ints.
•
Of course, unary minus would also reverse the sign of the operand.
•
Fortran, Ruby, Visual Basic and Ada have an exponentiation operator.
–
This operator has higher precedence than the unary minus operator so:
• Example: - A ** B is the same as
•
Page 315 lists the precedence of arithmetic operators for a few of the
common languages.
–
–
•
- ( A ** B)
Note: In Ada’s rem operator is the same as the % operator in Ruby and the Cbased languages.
The Ada mod operator is identical to rem when both operands are positive but
can be different when one or both are negative.
APL has a single level of precedence.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-8
Arithmetic Expressions: Operator
Associativity Rule
• The operator associativity rules for
expression evaluation define the order in
which adjacent operators with the same
precedence level are evaluated
• Typical associativity rules
– Left to right, except **, which is right to left
– Sometimes unary operators associate right to
left (e.g., in FORTRAN)
• In APL all operators associate right to left
• Precedence and associativity rules can be
overriden with parentheses
Copyright © 2007 Addison-Wesley. All rights reserved.
1-9
Arithmetic Expressions: Operator
Associativity Rule
• Interesting notes:
– In Fortran and Ruby the exponentiation operator is right
associative.
• a ** b ** c is evaluated as a ** (b ** c)
– In Ada, exponentiation is non-associative, which menas that the
expression a ** b ** c is illegal and must be written as
• (a ** b) ** c
or
a ** (b ** c)
– In Visual Basic the exponentiation operator, ^, is left associatve.
– Pages 316-317 lists the associativity rules for a few common
imperative languages.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-10
Arithmetic Expressions: Operator
Associativity Rule
• Interesting notes:
– Optimization and associativity: Some compilers for the imperative
languages can make use of the fact that some arithmetic operators are
mathmatically associative to perform some optimizations.
• In math ( A + B ) + C is always the same as A + ( B + C )
– But the fact that a mathematical operation is associative does not imply
that the corresponding computer arithmetic is precisely associative.
• In a computer, both floating-point representations and floating-point
arithmetic are only approximations of the mathematical counterparts.
• Can also be true for some integer operations, such as when adding very
large numbers and very small numbers.
–
–
A + B + C + D, where A and C are very large positive numbers and B and D are very
large negative numbers. If optimizations are done yielding an ordering of (A + C) + (
B + D) then overflow…
Use parentheses to show clear intent. (A + B ) + ( C + D)
– In APL, Ken Iverson, made the choice that there would be no precedence
rules and all operators would associate right to left.
• The expression A X B + C is evaluated as A X ( B + C)
Copyright © 2007 Addison-Wesley. All rights reserved.
1-11
Arithmetic Expressions: Operator
Associativity Rule
• Interesting notes:
– In Ruby, a purely OOPL, every data value including literals is an object.
– While Ruby supports the collection of arithmetic and logic operations of
the C-based languages, all of these operators are implemented as
methods.
– a + b is actually a class to the + method of the object referenced by a,
passing the object reference by b as a parameter.
– Since methods can be overriden by application programs, these
operators can be redefined.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-12
Arithmetic Expressions: Conditional
Expressions
• Conditional Expressions
– C-based languages (e.g., C, C++)
– An example:
average = (count == 0)? 0 : sum / count
– Evaluates as if written like
if (count == 0) average = 0
else average = sum /count
– Perl, JavaScript and Ruby also provide conditional
expressions.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-13
Arithmetic Expressions: Operand
Evaluation Order
A less commonly discussed design characteristic of
expressions is the order of evaluation of
operands.
•
•
1. Variables: fetch the value from memory.
2. Constants: sometimes a fetch from memory; sometimes
the constant is in the machine language instruction.
3. Parenthesized expressions: evaluate all operands and
operators first.
If neither of the operands of an operator has side
effects, then operand evaluation order is
irrelevant.
The Java language definition guarantees that
operands appear to be evaluated in left-to-right
order, eliminating side effects.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-14
Arithmetic Expressions: Operand Evaluation Order Potentials for Side Effects
• Functional side effects:
– Occurs when a function changes a two-way parameter or a nonlocal (global) variable.
• Problem with functional side effects:
– When a function referenced in an expression alters another
operand of the expression; e.g., for a parameter change:
a = 10;
/* assume that fun returns 10 but changes its parameter to 20 */
b = a + fun(a);
Scenario 1: a is fetched first, then added to fun(a)  result is 20
Scenario 2: fun(a) is evaluated first, then a is fetched  result is 30
Copyright © 2007 Addison-Wesley. All rights reserved.
1-15
Arithmetic Expressions: Operand Evaluation
Order - Potentials for Side Effects
• Functional side effects:
– Occurs when a function changes a two-way parameter or a nonlocal (global) variable.
• C example of functional side effects:
int a = 5;
int fun1() {
a = 17;
return 3;
} /* of fun 1 */
// global variable
// change to global
void main() {
a = a + fun1(); // value of a depends on order of evaluation
} /* of main */
Scenario 1: value of a is fetched first  result will be 8.
Scenario 2: function evalated first,
 result will be 20.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-16
Arithmetic Expressions: Operand Evaluation
Order - Potentials for Side Effects
Functional Side Effects
• Two possible solutions to the problem
1. Write the language definition to disallow functional side
effects
•
•
•
•
No two-way parameters in functions
No non-local references in functions
Advantage: it works!
Disadvantage: inflexibility of two-way parameters and
non-local references
2. Write the language definition to demand that operand
evaluation order be fixed
•
•
Disadvantage: limits some compiler optimizations
Note that purely functional languages do not have
this problem.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-17
Arithmetic Expressions: Operand Evaluation
Order - Potentials for Side Effects
•
•
Referential Transparency – a property whereby any two
expressions that have the same value can be substituted for
one another anywhere in the program without affecting the
action of the program.
Example:
–
–
–
•
Advantages:
–
–
•
result1 = (fun(a) + b) / (fun(a) – c);
temp = fun(a);
result2 = (temp + b ) / (temp – c);
Readability and reliability.
Programs can be reasoned about mathematically.
Note that purely functional languages have this property.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-18
Overloaded Operators
• Use of an operator for more than one purpose is called operator
overloading
• Common example: + for int and float addition
• Some have the potential for errors
– In C the use of the operator & for address-of along with logical bitwise
AND operations.
– Loss of compiler error detection (omission of an operand should be a
detectable error)
– Some loss of readability
• These types of problems can be avoided by using distinct operator
symbols for differing operations.
– Example: Pascal’s div for integer division.
• Good decision or bad decision?
– JavaScript avoids this problem by not having any integer arithmetic.
– In PHP if the result of int division yields a fractional part then the result
is a floating point vlaue.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-19
Overloaded Operators (continued)
• C++ and Ada allow user-defined
overloaded operators.
• Potential problems:
– Users can define nonsense operations such as
multiplication for +.
– Readability may suffer, even when the operators
do make sense.
–
• Consider A * B + C * D for
• MatrixAdd(MatrixMult(A, B), MatrixMult(C, D))
Copyright © 2007 Addison-Wesley. All rights reserved.
1-20
Type Conversions
•
A narrowing conversion is one that converts an object to a type that cannot include all
of the values of the original type e.g., float to int
–
•
A widening conversion is one in which an object is converted to a type that can include
at least approximations to all of the values of the original type e.g., int to float
–
•
In java:
• short to byte or char
• char to byte or short
• int to byte, short or char
• long to byte, short, char or int
• float to byte, short, char or int, or long
• double to byte, short, char or int, long, or float
In java:
• byte to short, int, long, float, or double
• ….
Note that even a widening conversion can be problematic.
–
Consider a 32 bit int conversion to 32 bit float.
• The 9 decimal digits of precision for int converted to only seven decimal
digits of precision of the float.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-21
Type Conversions: Mixed Mode
•
A mixed-mode expression is one that has operands of different types.
•
A coercion is an implicit type conversion.
•
Disadvantage of coercions:
•
In most languages, all numeric types are coerced in expressions, using widening
conversions.
–
–
A decrease in the ability of the compiler to detect “type errors”
Java Example:
int a;
float b, c, d;
…
d = b * a;
•
// Okay in java
In Ada, there are virtually no coercions in expressions.
A : Integer;
B, C, D : Float;
…
C := B * A;
Copyright © 2007 Addison-Wesley. All rights reserved.
Error in Ada
1-22
Explicit Type Conversions
• Explicit Type Conversions
• Called casting in C-based language
• Examples
– C: (int) angle
– Ada: Float(sum)
Note that Ada’s syntax is similar to function
calls
Copyright © 2007 Addison-Wesley. All rights reserved.
1-23
Type Conversions: Errors in Expressions
• Errors in the evaluation of expressions can occur in several cases.
– In cases of type coercions.
–
• If a languages requires type checking then operand errors cannot occur.
– Inherent limitations of arithmetic
• division by zero in Math is not possible.
– Limitations of computer arithmetic
• Overflow or Underflow
– These types of exceptions can be ignored by the run-time system.
• Some languages provide facilities for the detection and handling of these
exceptions.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-24
Relational and Boolean Expressions
•
Relational Expressions
–
Use relational operators and operands of various types
–
Evaluate to some Boolean representation
–
Operator symbols used vary somewhat among languages
•
>, <, .GT., .LT., etc.
• JavaScript and PHP
–
“7” == 7
vs.
“7” === 7
• Ruby uses == for equality with coercions and eq1? For equality tests without
coercions.
–
In general, relational operators have lower precedence than the arithmetic
operators.
• a+1>2*b
–
Page 328 shows the syntax of relational operators in some common PLs.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-25
Relational and Boolean Expressions
• Boolean Expressions
– Operands are Boolean and the result is Boolean
– Example operators
FORTRAN 77
FORTRAN 90
C
Ada
.AND.
.OR.
.NOT.
and
or
not
&&
||
!
and
or
not
xor
Copyright © 2007 Addison-Wesley. All rights reserved.
1-26
Relational and Boolean Expressions: No
Boolean Type in C
• C has no Boolean type--it uses int type with 0 for
false and nonzero for true.
• One odd characteristic of C’s expressions:
– a < b < c is a legal expression,
– but the result is not what you might expect:
• The left operator is evaluated, producing 0 or 1
– The evaluation result is then compared with the third
operand (i.e., c)
• Consider: 8 < 7 < 1
Copyright © 2007 Addison-Wesley. All rights reserved.
1-27
Relational and Boolean Expressions:
• Some languages provide two sets of the
binary logic operators.
• Perl and Ruby provide
– two forms of AND
– &&
– and (has lower precedence than its && counterpart)
– two forms of OR
– ||
– or (has lower precedence than its || counterpart)
– Also, the precedence of && is higher than ||,
while the spelled out forms have equal
precedence!
Copyright © 2007 Addison-Wesley. All rights reserved.
1-28
Relational and Boolean Expressions:
Operator Precedence
• Precedence of C-based operators
prefix ++, -unary +, -, prefix ++, --, !
*,/,%
binary +, <, >, <=, >=
=, !=
&&
||
Copyright © 2007 Addison-Wesley. All rights reserved.
1-29
Short Circuit Evaluation
•
Definition: an expression in which the result can be determined without evaluating all of the operands and/or operators.
•
Example: (13*a) * (b/13–1)
If a is zero, the result will be 0, since 0 times any number is zero, so there is no need to evaluate (b/13-1)
However, this type of shortcut is never taken since it cannot be detected very easily.
•
Example: (a >= 0) && (b < 10)
If a is less than 0, making a >= 0 false, there is no need to evaluate (b <
10). This shortcut can be easily discovered during execution.
•
Problem with languages that do not provide for non-short-circuit evaluation
index = 1;
while (index <= length) && (LIST[index] != value)
index++;
If a language provides short-circuit evaluation of Boolean expressions, then this is okay.
•
Potential problem with languages that provide short-circuit evaluation and side-effects in expressions.
–
(a > b) || ( ( b++) / 3)
–
These problems can be solved by providing additional operators that will cause full-evaluation of an expression to occur in all
cases.
•
•
Example the C-based languages use & and | for this purpose.
Ada provides the two-word operators and then and or else to specify that short-circuit evaluation is to be used.
Index := 1;
While (Index <= Listlen) and then (List (Index) /= Key)
loop
Index := Index + 1;
end loop;
•
All of the operators in Ruby and Perl are short-circuit.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-30
Assignment Statements
• The general syntax
<target_var> <assign_operator> <expression>
• The assignment operator
= FORTRAN, BASIC, PL/I, C, C++, Java
:= ALGOLs, Pascal, Ada
• Obviously, using = as the assignment operator and overloaded as
the relational operator for equality can lead to many errors and
therefore a bad design decision.
• Example: if (x = y) will not be detected as an error in this case.
• In the C-based languages the = operator can be embedded in
expressions.
– a = b = c; is possible along with if ( a > (b = c) ) …
• Design choices have varied widely.
– Fortran and Ada require that an assignment can only appear as a standalone statement and the destination must be a single variable.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-31
Assignment Statements: Conditional
Targets
• Conditional targets (C, C++, and Java)
(flag)? total : subtotal = 0
Which is equivalent to
if (flag)
total = 0
else
subtotal = 0
Copyright © 2007 Addison-Wesley. All rights reserved.
1-32
Assignment Statements: Compound
Operators
• A shorthand method of specifying a
commonly needed form of assignment
• Introduced in ALGOL; adopted by C
• Example
a = a + b
is written as
a += b
Copyright © 2007 Addison-Wesley. All rights reserved.
1-33
Assignment Statements: Unary
Assignment Operators
• Unary assignment operators in C-based
languages combine increment and
decrement operations with assignment
• Examples
sum = ++count (count incremented, added to sum)
sum = count++ (count incremented, added to sum)
count++ (count incremented)
-count++ (count incremented then negated due to
right to left associativity)
Copyright © 2007 Addison-Wesley. All rights reserved.
1-34
Assignment as an Expression
•
In C, C++, and Java, the assignment statement produces a result and can be
used as operands
•
An example:
while ((ch = getchar())!= EOF){…}
–
–
•
first the assignment statement
ch = getchar() is executed
(due to the parentheses)
then the result (assigned to ch) is used as a conditional value for the while
statement
The disadvantage of allowing this type of side effect can hinder readability.
–
Example: the previous expression must be read as a list of instructions…
–
Example: a = b + (c = d / b++) -1;
Copyright © 2007 Addison-Wesley. All rights reserved.
1-35
List Assignments
• Perl and Ruby provide multiple target, multiplesource assignemnt statements.
• Example in Perl:
– ($first, $second, $third) = (20, 40, 60);
– ($first, $second) = ($second, $first);
– Excess variables on the rhs are ignored as in:
• ($first, $second, $third) = (20, 40, 60, 70);
– Excess variables on the lhs are set to undef as in:
– ($first, $second, $third, $fourth) = (20, 40, 60);
Copyright © 2007 Addison-Wesley. All rights reserved.
1-36
Mixed-Mode Assignment
• Assignment statements can also be mixed-mode. That is the
type of the rhs is not the same as that of the lhs.
• For example, the rules for the code below will depend upon the
design decisions made for the particular language:
int a, b;
float c;
c = a / b;
• Fortran, C, C++ and Perl use coercion rules similar to those for
mixed-mode expressions.
• In Pascal, integer variables can be assigned to real variables, but
real variables cannot be assigned to integers.
• In Java and C#, only widening assignment coercions are done.
• In Ada, there is no assignment coercion.
• In Python and Ruby, types are associated with objects, not
variables, so there is no such thing as mixed-mode assignment.
Copyright © 2007 Addison-Wesley. All rights reserved.
1-37
Summary
•
•
•
•
•
Expressions
Operator precedence and associativity
Operator overloading
Mixed-type expressions
Various forms of assignment
Copyright © 2007 Addison-Wesley. All rights reserved.
1-38