Take Home Points

In this chapter we looked at our first Scala collections: Lists and Ranges. These are two types of sequence with different use cases:

We didn't cover this in the chapter but List and Range have a common supertype, Seq. This explains a few things:

Scala has a large collections library containing many different useful types: sequences, maps, and sets with mutable, immutable, lazy, and parallel variations. These types form a single inheritance hierarchy that provides consistent implementations of methods such as map, flatMap, filter, find, and so on.

We looked at one kind of transform operation in this chapter: the map method. map applies a user-specified function to every item in a sequence, returning a new sequence of the results:

List(1, 2, 3).map(x => x * 2)
// res0: List[Int] = List(2, 4, 6)

The key point about map is that it only makes sense in a world where we have functions that are also first class values. The same can be said for many of the other cohort of combinators such as filter, find, and flatMap. First class functions allow us to pass operations to these methods as parameters, separating user code from the implementational detail of allocating temporary buffers.

Because many transformation methods return sequences, we can chain calls to perform complex transformations in a series of simple steps. Here is an example that demonstrates the power of thie approach:

// Print all even numbers from 1 to 100 that are also divisible by 3:
(1 to 50).toList.
  map(x => x * 2).
  filter(x => x % 3 == 0).
  foreach(println)
// 6
// 12
// 18
// etc...

The structure of this computation looks similar to the structure of our Doodle programs: we build an intermediate representation by creating, combining, and transforming primitives, and perform side-effects at the end of the program. Obviously we've put less thought into this program than into Doodle, but it's interesting to note that even ad hoc functional programs can follow the same basic structure.