Expressions vs statements

11 November 2019
Tags: fundamentals

Statements are standalone units of execution which do not return any value. As such, it is clear that they are used to perform side effects in a program.

Functional vs imperative

To get an overview of the different paradigms you can refer to article Programming Paradigms Explained. Given the definitions above, it is clear that expressions constitute the building blocks of the functional paradigm, since everything should be always evaluated to give a value, and regardless of the time of invocation, given the same inputs should return same output values out of the expression. Statements, on the other hand, as said previously, are meant to provide side effects to the program, so it is clear that they can’t exist in purely functional programs. On the other hand, statements are fundamental blocks of the imperative style (together with expressions) as they are used to alter the control flow of the program through constructs such as conditionals, loops, procedures.

Examples

Here follow a few examples to illustrate the differences outlined above.

If conditionals

Some languages provide conditionals as expressions while others as statements; it is usually the case that languages that employ statements also provide an equivalent expression form (the ternary operator). If the conditional is an expression, it is evaluated to value, which means that it can be for example assigned to a variable or passed as a function argument; basically, it can be treated as any other value. In standard ML one can write for example:

val acidity = if ph < 7 then "ACID" else if ph = 7 then "NEUTRAL" else "BASE"

It is clear that, being an expression, the conditional is required by the language to provide a value no matter what, thus all possible cases should be considered and a value should be returned for each. In this example the else branches are not optional, because if the ph level is greater or equals to 7, there must be some other value you return.

If the conditional is a statement, it doesn’t return a value, so for example it cannot be assigned to a variable, but it is a sort of logical block containing instructions with side effects. In Python you could write an if statement like this:

acidity = ... # could be any value
...
if ph < 7:
	acidity = "ACID"
elif ph == 7:
	acidity = "NEUTRAL"
else:
	acidity = "BASE"

This snippet shows that, no matter which branch is taken, the statement mutates the value of the variable acidity. Note that it would be illegal syntax to assign this block to the variable acidity. Finally, the language does not enforce you to provide a value for all the possible values of ph, you could in fact only define the first if branch and ignore the other cases.

Loops

Imperative languages provide different constructs to loop over series of values or data structures (for, foreach, while, …​) which produce side effects. Functional languages instead do not provide a loop construct, but rely on the mechanism of recursion over data structures to implement it, since a value is returned out of it.

Languages mixing both paradigms

It is now clear how languages that mix both the functional and imperative (e.g. object-oriented) styles make you define a certain construct either as an expression or as a statement respectively. For example, in Kotlin the body of a function can be defined as: - functional style: fun f() = when {…​} the body is an expression and when it is evaluated to produce a value, this is assigned to the function. - oo style:

fun f(ch: Char) {
	ch = ch + 1
	print(ch)
	return ch
}

the body is a statement composed of a sequence of instructions producing side effects.

Wrap-up

We have seen that while expressions are evaluated to return a value, statements do not return any value, performing instead side effects. As such, programs written in the imperative style are constituted by both expressions and statements which implement some logic altering the state of the program (e.g. conditions, looping). The functional paradigm instead mandates the exclusive usage of expressions since by definition side effects are not admitted. The advantages of using expressions over statements is first of all that the program is contained from the side effects which would be introduced were you to use statements. Another advantage is that all constructs in the program are always evaluated to a value; as such, they can be passed around in the program as you would with simple values such as primitives or simple expressions. This favours composition, since the program itself is an expression made out of other expressions which produce a value. This means that the program can be passed around, returned or composed, allowing for further flexibility.