Functional composition in Scala

In Scala, it is very easy to chain function calls by using functional composition. By combining pure functions in this way, we can compose many functions in a very concise and easily testable manner.

Functions that are declared using the val keyword inherit both the compose and andThen functions (they do the same thing, the order is just reversed). This allows us to easily compose functions.

Calling compose will take the result of the second function and pass it as a parameter to the first function.

Calling andThen will take the result of the first function and pass it as a parameter to the second function.

Example:

val square: Int => Int = x => x * x
val increment: Int => Int = x => x + 1

val composedExample: Int => Int = square compose increment

Calling composedExample with an integer value would evaluate to square(increment(x)), so we would first increment, and then square the number:

scala> composedExample(5)
res0: Int = 36

Alternatively, we could use the andThen function to achieve g(f(x)):

val square: Int => Int = x => x * x
val increment: Int => Int = x => x + 1

val andThenExample: Int => Int = square andThen increment

Calling andThenExample with an integer value would evaluate to increment(square(x)), so we would first square, and then increment the number:

scala> andThenExample(5)
res1: Int = 26

 

When working with methods declared using the def keyword, we can easily convert them into functions using the ‘_ symbol:

def square(x: Int): Int = x * x
def increment(x: Int): Int = x + 1

val composedDefExample: Int => Int = square _ compose increment _
val andThenDefExample: Int => Int = square _ andThen increment _

scala> composedDefExample(5)
res2: Int = 36

scala> composedDefExample(5)
res3: Int = 26

TL;DR: Functional composition is a very easy concept that can be used to chain function calls, making code much more concise.

f(x) compose g(x) gives us f(g(x))
f(x) andThen g(x) using gives us g(f(x))

The power of sealed traits in Scala

Having improved a piece of code today by adding compile-time safety, I felt obliged to write a short explanation of sealed traits. For the Scala veterans, this will hopefully not be anything new.

Sealed traits can only be extended in the same files as they are declared – long story short, the JVM allows code to be loaded at runtime, so the compiler can’t scan the entire program to collect all of the subtypes. This ensures that the compiler knows about all the subtypes that extend the trait.

So what advantage does this limitation give us?

Take a look at the following code snippet and consider why it’s unsafe:

trait Color

case object Red extends Color
case object Blue extends Color
case object Green extends Color

def composePoem(color: Color): String = {
  color match {
    case Red => "Roses are red"
    case Blue => "Violets are blue"
  }
}

That’s right! We’re not handling the case of the color being Green in our match clause. This also means that, if in the future we decide to add another color, our composePoem function will break at runtime with a MatchError:

scala> composePoem(Green)
scala.MatchError: Green (of class Green$)
  at .composePoem(<console>:17)
  ... 36 elided

…Sealed trait to the rescue!

sealed trait Color

case object Red extends Color
case object Blue extends Color
case object Green extends Color

def composePoem(color: Color): String = {
  color match {
    case Red => "Roses are red"
    case Blue => "Violets are blue"
  }
}

By adding the sealed keyword, the compiler performs exhaustiveness checking and gives us a warning that the function would fail on the input “Green”:

<console>:15: warning: match may not be exhaustive.
It would fail on the following input: Green
         color match {
         ^

The compiler will thus tell us about every place in our code base that needs to be updated if we add more objects or classes that extend the sealed trait. We thus have stronger guarantees that our code is correct.

TL;DR: Use sealed traits to enable exhaustive matching. Issues highlighted at compile time are way better than issues highlighted at runtime.

Using Scala’s Future.apply efficiently

I recently browsed through the scala.concurrent.Future code and noticed that, in addition to Future.apply, there are three other constructors:

Future.successful – This creates a completed future.
Future.failed – This creates a completed future with a given exception.
Future.fromTry – This creates a completed future with either a successful result, or an exception.

The reason why these constructors are interesting, is because they create completed futures, whereas Future.apply starts an asynchronous computation to eventually complete the future.

Isn’t that the purpose of a future, though? In most cases, yes! I have, however, seen some cases where using some of the other constructors might be more efficient. Consider the following (non real-world) example:

case class User(name: String)

def retrieveUser(userName: String): Future[User] = {
  userName match {
    case "testUser" => Future(User("testUser"))
    case _ => Future(retrieveUserFromDB(userName))
  }
}

Clearly, if we have some constant value, it would be better to use the following instead:

case class User(name: String)

def retrieveUser(userName: String): Future[User] = {
  userName match { 
    case "testUser" => Future.successful(User("testUser")) 
    case _ => Future(retrieveUserFromDB(userName))
  } 
}

This will avoid the unnecessary asynchronous computation in the first case.

TL;DR: Use the 3 mentioned Future constructors when returning a Future that requires no asynchronous calculation.

Hello, world!

Hi there! My name is Pierre Marais. I’m a functional programmer working with cool technologies like Scala, Akka & Play.

The purpose of this blog is to share some of the new things I learn by reading coding books & blogs.