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 Javaforloop. 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
- If you don’t like the way I implemented
foreach, go ahead and implement it however you’d like. I recommend using recursion!