Expressions

Expression: Any valid combination of symbols that yields a value.

Example: Some expressions
40 \text{$+$} 2 # 42
3 \lt 7 # true

In most mainstream imperative languages, expressions can be classified in two types (though, some languages may blur the boundaries):

  1. Arithmetic Expressions (Yields Number)
  2. Boolean Expressions (Yields Boolean)

Note — Other kinds of expressions may yield objects (e.g., Strings)

Operators

Most expressions are composed of operators processing operands. Operators may be classified in several ways:

Arity

The arity of an operator is the number of operands it needs to yield a value.

Example: Arity
# Unary
++x
*p
not a

# Binary
5 \text{$+$} 27
a or b
a == b

# Ternary
x = expr1 ? expr2: expr3

Positioning

operator Positioning: Relative position of the operator wr.t. the operands

Example: Operator Positioning
# Prefix
++x

# Suffix
x++

# Infix
1 \text{$+$} 2

Order of Operations

It is very important to define this in a language!

Example: Simplest example

Suppose:

25 \text{$+$} 20 \text{$-$} 3

We could evaluate right-to-left or left-to-right. While these yield the same value, the programmer should know how is evaluated.

Example — Java expressions are generally left-to-right, like most languages.


This example is more ambiguous.

25 \text{$+$} 20 \large{*} 3

We can introduce parenthesis to force PEMDAS.

25 \text{$+$} (20 \large{*} 3)

Of course, most languages implement operator precedence so we don’t have to do this.

Precedence of Operators

Hierarchy that specifies the relative strength with which operators bind to operands, determining order of evaluation.

Example: Simple arithmetic precedence

Most languages do this precedence:

  1. Multiplication/Division/Remainder
  2. Addition/Subtraction

Associativity

Associativity rules must also be specified whether association is left-to-right or right-to-left.

Example: Associativity
5 \text{$+$} 4 \text{$+$} 3

How does addition associate? Which plus is evaluated first?

If you associate from the left, the first plus (5+4) runs first, and vice versa.

This must be defined in the languages, especially if you have expressions that have side-effects.

Side-Effects

An expression with side-effects produces a destructive of memory.

Definition — A side effect is any destructive update of memory during a program.

Example: Side-Effects

Simple Example:

y := 0
x := 1
z := (x++) \text{$+$} y \text{$+$} x

When this executes, z will be modified. But before that happens, something else in touched. In this case, x is touched, which is a side-effect.

If we evaluate left-to-right, we get z = 1+0+2= 3, x = 2.

If we evaluate right-to-left, we get z = 1+0+1= 2, x = 2.

Another Example:

Here is an wonky expression that breaks the commutativity of or.

# Behavior: if x \gt 0, y increments
x \gt 0 || y++ \gt 0

# Behavior: y always increments
y++ \gt 0 || x \gt 0

Lesson — Side-effects are evil and lead to error-prone code.

Referential Transparency

An expression is referentially transparent when substituting the expression with the value it yields doesn’t change the program’s behavior.

Example: Referential Transparency
# Referentially Transparent
x = 1 \text{$+$} 2

# Not Referentially Transparent
x = (x++) \text{$+$} 2

Operator Overloading

Operator is overloaded if it has more than one operation depending on the type of operands.

Example: Operator Overloading

In Java, we can overload methods. Our abstract idea is “the function has different behaviors/parameters depending on how we use it”. Likewise, operators can be overloaded.

// Adding floats
3 + 4

// Adding integers
1.0 + 5.6

// Concatenating strings
"Good" + " " + "Dog"

Mixed-Mode Expressions

An expression is mixed-mode when it includes operands of different types.

Designer Choices:

Example: Mixed-Mode Expressions
# Int
int x := 42
# Float
int y := 1.6

# Mixed-Mode
int z := x \text{$+$} 3 \large{*} y \text{$-$} 2

Note — You must design the rules clearly!

Overflow and Underflow

Overflow: When an operation on an integer goes past the maximum representable value.

Underflow: When an operation on a float goes below the smallest representable value.

Example: Overflow and Underflow
# Overflow
int x = 7;
x ^ 2^{32}

# Underflow
float y = 7.0;
y^{-64}

Some languages error, some just let it happen.

Boolean Expressions

Operators

Relational Operators:

Logical Operators:

Short Circuiting

Form of lazy evaluation in which the second operand of a binary operation is evaluated if the first operand is true.

DefinitionLazy Evaluation: Any technique that delays the evaluation of an expression as much as possible to save.

Example: Short Circuiting
# If x is false, we can skip evaluating 2nd operand
x and y

# If x is true, we can skip evaluating 2nd operand
x or y

Note — This does not play well with side-effects.