Concepts of Programming Languages: Expressions and Assignment Statements
Foundations of Expressions and Evaluation
Expressions are the fundamental means by which computations are specified within a programming language.
Understanding expression evaluation requires familiarity with the specific orders of operator and operand evaluation.
In imperative programming languages, the assignment statement plays a dominant and essential role in the language's essence.
Arithmetic Expressions: Structure and Design Issues
Arithmetic evaluation was a primary motivator for the development of the very first programming languages.
Composition: Arithmetic expressions consist of operators, operands, parentheses, and function calls.
Operator Placement and Arity: - A unary operator has one operand. - A binary operator has two operands. - A ternary operator has three operands. - In most languages, binary operators use infix notation. - In Scheme and LISP, binary operators use prefix notation. - Perl also includes some prefix binary operators. - Unary operators are typically prefix, but the
++and--operators in C-based languages can be either prefix or postfix.Design Issues for Arithmetic Expressions: - Determining operator precedence rules. - Determining operator associativity rules. - Defining the order of operand evaluation. - Managing operand evaluation side effects. - Handling operator overloading. - Addressing type mixing within expressions.
Operator Precedence and Associativity
Operator Precedence Rules: These rules define the order in which "adjacent" operators of different precedence levels are evaluated.
Typical Precedence Levels (Highest to Lowest): 1. Parentheses 2. Unary operators 3.
**(if the language supports exponentiation) 4.*,/(Multiplication and Division) 5.+,-(Addition and Subtraction)Operator Associativity Rules: These rules define the evaluation order for adjacent operators that share the same level of precedence. - Typical Rules: Left to right evaluation, except for
**, which usually associates right to left. - Language Variations: Unary operators sometimes associate right to left (e.g., in FORTRAN). - APL Exception: In APL, all operators have equal precedence and all associate right to left.Precedence and associativity rules can be explicitly overridden through the use of parentheses.
Language-Specific Expression Models
Ruby: - All arithmetic, relational, and assignment operators are implemented as methods. - Array indexing, shifts, and bit-wise logic operators are also methods. - A consequence of this design is that application programs can override all of these operators.
Scheme and Common Lisp: - All arithmetic and logic operations are performed via subprograms that are explicitly called.
Conditional Expressions (C-Based Languages): - Examples include C and C++. - Example syntax:
. - This evaluates as follows:.
Operand Evaluation and Functional Side Effects
Rules for Operand Evaluation: - Variables: The value is fetched from memory. - Constants: The value is fetched from memory or is embedded within the machine language instruction. - Parenthesized Expressions: All internal operands and operators are evaluated first. - The most complex case occurs when an operand is a function call.
Functional Side Effects: These occur when a function modifies a two-way parameter or a non-local variable. - Problem: A functional side effect occurs when a function referenced in an expression alters another operand within that same expression. - Example for a parameter change: -
-/* ext{Assume } fun ext{ changes its parameter } */-Potential Solutions: 1. Disallow functional side effects in the language definition by banning two-way parameters and non-local references in functions. - Advantage: This solution is effective. - Disadvantage: It creates inflexibility due to the lack of non-local references and the limitations of one-way parameters. 2. Demand that the operand evaluation order be fixed in the language definition. - Disadvantage: This limits various compiler optimizations. - Note: Java requires that operands appear to be evaluated in a fixed order.
Referential Transparency
Definition: A program has the property of referential transparency if any two expressions in the program with the same value can be substituted for one another anywhere in the program without affecting the program's action.
Comparison Example: -
--- Ifpossesses no side effects, then. If side effects exist, referential transparency is violated.Advantages: Program semantics are much easier to understand when referential transparency is maintained.
Functional Languages: Programs in pure functional languages are referentially transparent because they do not have variables. Functions cannot have state (stored in local variables), and values used from outside must be constants.
Operator Overloading and Type Conversions
Operator Overloading: The use of an operator for more than one purpose. - Common examples: Use of
+for bothandtypes. - Troubling examples: The*operator in C and C++ can lead to a loss of readability and compiler error detection (e.g., omitting an operand should be a detectable error).User-Defined Overloading: C++, C#, and F# allow for user-defined overloaded operators. - Advantage: Can aid readability and make expressions appear natural by avoiding explicit method calls. - Disadvantage: Users can define nonsense operations, and readability may suffer even if the operator usage makes sense.
Narrowing Conversion: Converts an object to a type that cannot include all values of the original type (e.g.,
to).Widening Conversion: Converts an object to a type that can include at least approximations of all values of the original type (e.g.,
to).Mixed-Mode Expressions: An expression containing operands of different types.
Coercion: An implicit type conversion. - Disadvantage: Coercions decrease the compiler's ability to detect type errors. - In most languages, numeric types are coerced in expressions using widening conversions. - Exceptions: In ML and F#, there are no coercions in expressions.
Explicit Type Conversions (Casting): Called "casting" in C-based languages. - Example (C):
. - Example (F#):(Note that F# syntax is similar to function call syntax).
Relational and Boolean Expressions
Relational Expressions: Use relational operators and operands of various types to evaluate to a Boolean representation. - Variable Symbols:
!=,/=,~=,.NE.,<>,#. - JavaScript and PHP: Feature identity operators===and!==. These are similar to==and!=but do not perform coercion on their operands.Boolean Expressions: Operands and results are both Boolean. - C89: Lacks a Boolean type; it utilizes the
type, whererepresents false and any nonzero value represents true. - Odd Characteristic of C: The expressiona < b < cis legal. It evaluates the left operator first (producingor), and the result is then compared with.Errors in Expressions: Often caused by inherent arithmetic limitations (e.g., division by zero) or computer arithmetic limitations (e.g., overflow). These are frequently ignored by the run-time system.
Short-Circuit Evaluation
Definition: An expression in which the result is determined without evaluating all of its operands and/or operators.
Example:
. Ifis zero, evaluating the second halfis unnecessary.Potential Problems with Non-Short-Circuit Evaluation: -
-while (index eq length) ext{ } && ext{ } (LIST[index] eq value) ext{ } index++- If, evaluatingwill cause an indexing problem (assuming the list islong).Language Support: - C, C++, and Java: Use short-circuit evaluation for Boolean operators (
&&and) but provide bitwise operators (&and) that are not short-circuit. - Ruby, Perl, ML, F#, and Python: All logic operators are short-circuit evaluated.Risk: Short-circuit evaluation can expose problems related to side effects, e.g.,
(a > b) ext{ } || ext{ } (b++ / 3).
Assignment Statements and Syntax
General Syntax:
<target_var> <assign_operator> <expression>.Assignment Operators: -
=: Used in Fortran, BASIC, and C-based languages. -:=: Used in Ada.Conflict: The use of
=can be problematic when it is overloaded for the relational equality operator; thus, C-based languages use==for relational equality.Conditional Targets (Perl): - Example:
. - Equivalent logic:.Compound Assignment Operators: A shorthand for specifying common assignments, introduced in ALGOL and adopted by C-based languages (e.g.,
can be).Unary Assignment Operators (C-based): Combine increment/decrement with assignment. -
(count incremented, then assigned to sum). -(count assigned to sum, then incremented). -(count incremented). -(count incremented then negated).Assignment as an Expression: In C-based languages, Perl, and JavaScript, the assignment statement produces a result. - Example:
. The result ofis used as a conditional value. - Disadvantage: Creates another form of expression side effect.Multiple Assignments (Perl and Ruby): Allows multiple-target, multiple-source assignments. - Example:
. - Interchange:is legal and performs a swap.
Assignment in Functional Languages
Identifiers in functional languages are names of values only.
ML: - Names are bound to values using
val(e.g.,). - If a subsequentvalforfruitappears, it is considered a new and different name.F#: - Uses
let, which is similar tovalin ML, except thatletalso creates a new scope.
Mixed-Mode Assignment Coercion Rules
Assignment statements can be mixed-mode.
Fortran, C, Perl, and C++: Any numeric type value can be assigned to any numeric type variable.
Java and C#: Only widening assignment coercions are performed.
Ada: No assignment coercion is permitted.