Learn Scala 3 Fast: Collections: The foreach Method and Anonymous Functions

The Scala List class gave us a nice way to demonstrate for loops and expressions, so I took a little time to show those. As you’ll see in the next few lessons, another reason I showed those examples is because they give me a way to explain some of the most commonly-used methods that are available on sequence classes like List.

As you’ll see, most of the methods I’m about to demonstrate are replacements for custom for expressions. They all loop over your collection, and do something different with that collection, based on the algorithm you supply. You often supply your algorithm as a small snippet of code that’s known as an anonymous function. Everything about this approach makes your code easier to read and maintain.

Back when I first started learning Scala in 2010, these methods were definitely not standard, but since then they have been adopted by other languages like Java, Swift, Kotlin, etc.

The Scala/List foreach method

The foreach method is available on all Scala sequence classes. It basically has a built-in for loop that lets you specify what you want to do with each element. foreach does not return anything useful, so it’s always used for some sort of side effect, such as printing:

val ints = List(1, 2, 3)
ints.foreach(println)       // prints 1, 2, and 3 on separate lines

A first look at anonymous functions

That second line of code uses something known as an anonymous function. Let’s look at how it works. First, given this list:

val ints = List(1, 2, 3)

the long version of how you could write the previous code looks like this:

ints.foreach(i => println(i))

This can be read as, “For every element i in the list ints, print that element using the println function.” You can see where the variable i is used in the code here:

ints.foreach(i => println(i))
             ^            ^

In this code you can think of the => symbol as being a transformer. It transforms the thing on the left — the variable i — into the thing on the right, which in this case is a println function:

// the variable 'i' is transformed into a println statement
i => println(i)

In this specific example it turns out that there’s something interesting — and also common — going on here:

  • Only one variable comes out of the list at a time
  • That variable is referenced only one time on the right side of the => symbol

For most methods on sequences — such as foreach — the first condition is usually true. When the second condition is also true, Scala lets you take a few additional shortcuts. The first shortcut is that Scala lets you use the _ character to refer to that single element:

ints.foreach(println(_))

This shortens your code, but still leaves it being readable. However, since that _ really doesn’t add any value, Scala lets you omit it completely:

ints.foreach(println)

In summary, you could write the code like this:

ints.foreach(i => println(i))

but the Scala way is to write it like this:

ints.foreach(println)

foreach is like a 'for' loop

One more note: The foreach method is often similar to writing a for loop. For instance, given this List[String]:

val strings = List("a", "bb", "ccc")

these two approaches produce the same result:

for s <- strings do println(s.length)
strings.foreach(s => println(s.length))

What I found in my own experience — being mostly familiar with Java at the time — was that when I started working with Scala I kept writing for loops, but these days I always reach for methods like foreach, filter, and map, in combination with small anonymous functions.

I like to think of anonymous functions as being small snippets of code that are easy to read.

Higher-Order Functions

The foreach method and the two other sequence methods I’m about to show — filter, and map — are technically known as Higher-Order Functions, or HOFs.

If that term sounds scary, fear not, it just means that a method like foreach, which is an HOF, can take a function as an input parameter. As you’ll see in the next several lessons, this lets us pass little snippets of code into foreach, filter, and map. Those HOFs are each written in slightly different ways, so they apply your custom code snippet to the sequence to achieve a desired effect.

In the book, Learn You A Haskell For Great Good!, the author makes this statement:

“Haskell functions can take functions as parameters and return functions as return values. A function that does either of those is called a higher order function. Higher order functions aren’t just a part of the Haskell experience, they pretty much are the Haskell experience.”

Similarly, they are pretty much the Scala experience as well. Once you get used to them, you’ll be writing expressive code: concise, and still readable.

(In Scala, functions can also return functions, and I show how to do that in the Scala Cookbook and Functional Programming, Simplified.)

Exercises

The exercises for this lesson are available here.

books by alvin