A Note About Expression-Oriented Programming
This chapter isn’t a lesson so much as it as an observation — a short note that the FP code I’m writing in this book also falls into a category known as Expression-Oriented Programming, or EOP.
In fact, because Pure FP code is more strict than EOP, FP is a superset of EOP. As a result, we just happen to be writing EOP code while we’re writing Scala/FP code.
Therefore, my goals for this lesson are:
To show the difference between statements and expressions
To briefly explain and demonstrate EOP
To note that all “Pure FP” code is also EOP code
I wrote about EOP in the Scala Cookbook, so I’ll keep this discussion short.
When you write pure functional code, you write a series of expressions that combine pure functions. In addition to this code conforming to an FP style, the style also fits the definition of “Expression-Oriented Programming,” or EOP. This means that every line of code returns a result (“evaluates to a result”), and is therefore an expression rather than a statement.
As noted in the quote at the beginning of this chapter, statements do not return results and are executed solely for their side effects.
An expression has the form:
val resultingValue = somePureFunction(someImmutableValues)
Contrast that with the OOP “statement-oriented code” I used to write:
order.calculateTaxes()
order.updatePrices()
Those two lines of code are statements because they don’t have a return value; they’re just executed for their side effects.
In FP and EOP you write those same statements as expressions, like this:
val tax = calculateTax(order)
val price = calculatePrice(order)
While that may seem like a minor change, the effect on your overall coding style is huge. Writing code in an EOP style is essentially a gateway to writing in an FP style.
I’m tempted to write about “The Benefits of EOP,” but because I already wrote about “The Benefits of Functional Programming” in a previous lesson, I won’t repeat those points here. Please see those chapters to refresh your memory on all of those benefits.
A key point of this lesson is that when you see statements like this:
order.calculateTaxes()
order.updatePrices()
you should think, “Ah, these are statements that are called for their side effects. This is imperative code, not FP code.”
As I noted in the Scala Cookbook, these are obviously expressions:
val x = 2 + 2
val doubles = List(1,2,3,4,5).map(_ * 2)
But it’s a little less obvious that the if/then construct can also be used to write expressions:
val greater = if (a > b) a else b
Note: In Java you need the special ternary operator syntax to write code like that.
The match
construct also returns a result, and is used to write expressions:
val evenOrOdd = i match {
case 1 | 3 | 5 | 7 | 9 => println("odd")
case 2 | 4 | 6 | 8 | 10 => println("even")
}
And try/catch blocks are also used to write expressions:
def toInt(s: String): Int = {
try {
s.toInt
} catch {
case _ : Throwable => 0
}
}
As you’ll see in the upcoming lessons on recursion, match
expressions are a big part of the Scala language, and because they evaluate to a value, you’ll often write the first part of recursive functions like this:
def sum(list: List[Int]): Int = list match { ...
When every line of code has a return value it is said that you are writing expressions, and using an EOP style. In contrast, statements are lines of code that do not have return values, and are executed for their side effects. When see statements in code you should think, “This is imperative code, not FP code.”
As noted in this lesson, because EOP is a subset of an FP style, when you write Scala/FP code you are also writing EOP code.
Given this background, the next lesson shows how writing Unix pipeline commands also fits an EOP style, and in fact, an FP style.