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
.
Scala replacements for custom 'for' expressions
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.)
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
Exercises
The exercises for this lesson are available here.