How to Make Sequence Work in a Simple Scala `for` Loop

So far I have this Sequence class:

case class Sequence[A](initialElems: A*) {

    private val elems = scala.collection.mutable.ArrayBuffer[A]()

    // initialize
    elems ++= initialElems

}

With that code I can create new Sequence instances like this:

val strings = Sequence("a", "b", "c")
val nums = Sequence(1, 2, 3, 4, 5)

Next, I’ll modify Sequence so I can use it as a generator in a for loop.

Note: I intentionally use the word “loop” in this lesson because all I’m trying to do is to loop over the elements in the Sequence, like a Java for loop. I’m specifically not trying to write for/yield expressions.

Trying to use Sequence in a simple `for` loop

To get started, let’s see what happens if I try to use a Sequence in a simple for loop. When I paste these two lines of code into the Scala REPL:

val ints = Sequence(1, 2, 3)
for (i <- ints) println(i)

I see this error after the for loop:

scala> for (i <- ints) println(i)
<console>:14: error: value foreach is not a member of Sequence[Int]
       for (i <- ints) println(i)
                 ^

The bad news is that Sequence won’t work in a simple for loop. But the good news is that the Scala compiler error tells me what’s wrong:

"value foreach is not a member of Sequence[Int]"

How to modify Sequence so it can be used as a `for` loop generator

The error message tells me that this for loop won’t work because Sequence doesn’t have a foreach method, so I’ll go ahead and implement one.

Because (a) Sequence uses an ArrayBuffer behind the scenes, and (b) I’m not concerned with how I implement the foreach method, I’ll just piggyback on the ArrayBuffer’s foreach method:

def foreach(block: A => Unit): Unit = {
    elems.foreach(block)
}

(As I mentioned in the last lesson, for the purposes of understanding how the for expression works I don’t care how I implement a foreach method, I just want to create one as simply as possible to see if that lets me use Sequence inside of for.)

Adding foreach makes my complete Sequence class look like this:

case class Sequence[A](initialElems: A*) {

    private val elems = scala.collection.mutable.ArrayBuffer[A]()

    // initialize
    elems ++= initialElems

    def foreach(block: A => Unit): Unit = {
        elems.foreach(block)
    }

}

When I paste that class into the REPL, and then paste this code in as well:

val ints = Sequence(1,2,3)
for (i <- ints) println(i)

I see that Sequence now works as a for loop generator:

scala> for (i <- ints) println(i)
1
2
3

Excellent. Let’s move on to the next step.

Exercises

  1. If you don’t like the way I implemented foreach, go ahead and implement it however you’d like. I recommend using recursion!

books by alvin