A practical guide to breakOut

2017-05-27

In this post I will be reviewing scala.collection.breakOut from an application developer's perspective rather than a functional programming enthusiast. I will discuss why one would want to use it and how to recognize when it is applicable.

When I first saw breakOut, it seemed like an extremely intimidating concept and a little like black magic. It certainly didn't help that I found explanations of breakOut intermingled with the equally intimidating concept of CanBuildFrom. This is a shame because, with proper application, breakOut can make your code run faster.

The full code sample in this blog can be found at github.

Why we care

val list = List("one", "two", "three", "four")

val expensiveMap = list     // type Map[Int, String] is infered by the compiler
  .map(n => n.length -> n)  // 1
  .toMap                    // 2

Since Scala eager evaluation by default, this code ends up being memory inefficient. We first create an intermediate list at line (1) and then convert it to a Map on line (2). Ideally we could do it all in one step. Well thanks to breakOut we can!

import scala.collection.breakOut
val list = List("one", "two", "three", "four")

val efficientMap: Map[Int, String] = list   // you need to specify the type
  .map(n => (n.length, n))(breakOut)

This results in the Map we want without the intermediate list. Win!

When to use

So when should we use breakOut? An easy way to remember when to use it is if we have the following list of conditions:

Conclusion

Scala has a robust immutable collections library, which has a tendency to make it more GC heavy. However, with some attention to the implementation details, it is possible to remain efficient and functional.