Learn Scala 3 Fast: Collections: The List Class

A sequence in Scala is an ordered list of values, meaning that the values are returned in the order you put them in. Scala has a few different types of sequences that you can use for different needs, including List, Vector, and ArrayBuffer. But for our purposes, a good one to start with is List.

Scala’s List class is immutable, meaning that its elements can’t be changed and the list can’t be resized. It’s implemented as a linked-list, so it’s good for small lists, but if you want to have fast access to its one-millionth or one-billionth element, you’ll want to use a Vector instead. (I discuss this more as we go along.)

NOTE: For reasons of efficiency and performance, the different sequence classes store your elements in different ways, but the important part is that they are returned to you in the proper order.

Using Scala’s List class

These examples show how to create new lists of different types:

val ints = List(1, 2, 3)
val doubles = List(1.1, 2.2, 3.3)
val names = List("Aleka", "Christina", "Alvin")

As shown, you usually don’t need to explicitly declare the type of the List, but when you want or need to do that, you can:

val ints: List[Int]       = List(1, 2, 3)
val doubles: List[Double] = List(1.1, 2.2, 3.3)
val names: List[String]   = List("Aleka", "Christina", "Alvin")

In that code, List[Int] can be read as “A list of integers,” List[Double] can be read as “A list of double values,” and so on.

Typically you’ll only explicitly show the data type when it isn’t 100% obvious what’s contained in the List. That won’t be a big problem now, but when your code gets more complicated there can be situations where you’ll want to explicitly declare the type like this.

Accessing List elements

When you need to access the elements stored in a List, you access them by their index number, like this:

list(0)    // the first element
list(1)    // the second element

Like most other programming languages, Scala is 0-based when it comes to working with indexes on sequences, so the first element is referred to as “element 0,” the second is “element 1,” etc. Here’s a complete example using a List[String] — a list of strings — that shows how this works:

val list = List("a", "b", "c")

println(list(0))    // prints a
println(list(1))    // prints b
println(list(2))    // prints c

As you’ll see throughout this book, using parentheses to access elements in a collection is used consistently in Scala.

Scala Lists are immutable

As mentioned, the List class is an immutable data structure, meaning that you can’t add, update, or remove elements, and you can’t resize an existing list. For example, given this List[Int]:

val ints = List(1, 2, 3)

these attempts to add or update elements will fail to compile:

ints += 4       // error
ints(0) = 10    // error

The next lesson begins to show the correct ways to update lists.

Discussion

If the List class being immutable seems like a big restriction, fear not! There are a few things that will ease your concerns.

First, if you’re only interested in OOP, Scala has other types of sequence classes that are mutable, meaning that you can modify their elements. I’ll show those shortly.

Second, if you have at least a mild interest in FP, you’ll find that it’s surprising how often you don’t need a mutable sequence class. Because of this, I often reach for the List class first, and then change it to a mutable sequence if I really need one.

Third, as I mentioned earlier, another approach is to create a as a var variable, in which case you can then assign the new result back to a:

var a = List(1, 2, 3)
a = a ++ List(4, 5)      // a: List(1, 2, 3, 4, 5)

Some OOP developers I have talked to really like this approach of using (a) an immutable sequence with (b) a mutable variable.

A performance note

When you have a small sequence that contains just a few elements, it doesn’t matter too much what sequence class you use. But when you have large lists, you may want to use a Vector or ArrayBuffer instead of a List. The process for choosing a sequence type is explained in the lessons that follow, but for now just note that Vector is immutable just like List, but it works much faster with large lists when you need to access an element directly, like list(10_000_000). And ArrayBuffer is like a mutable version of Vector, so you’ll use it when you have a sequence that you’ll constantly be modifying.

Those things being said, I’ll continue to use List in the lessons that follow because it’s a nice class for small, immutable sequences.

Exercises

The exercises for this lesson are available here.

books by alvin