What must I do in order to be able to return an Iterator from a method/class ? How would one add that trait to a class?
3 Answers
You can extend Iterator, which will require that you implement the next
and hasNext
methods:
class MyAnswer extends Iterator[Int] {
def hasNext = true
def next = 42
}
But, you will get more flexibility if you extend Iterable, which requires you implement elements
(or iterator
in 2.8):
class MyAnswer extends Iterable[Int] {
def iterator = new Iterator[Int] {
def hasNext = true
def next = 42
}
}
A common idiom seems to be to expose an iterator to some private collection, like this:
class MyStooges extends Iterable[String] {
private val stooges = List("Moe", "Larry", "Curly")
def iterator = stooges.iterator
}

- 13,186
- 3
- 44
- 32
-
There is't a way to send private messages but I'd like to pose a question: could you perhaps point me to a usage of the common idiom you mention? If not, what could it be useful for? Why not just return the List? Wouldn't this idiom be less efficient? (Also: I've seen that Iterable[A] "trick" a few times and it seems to be one of the fastest ways to create something collection-like, are there any "alternatives" to this approach? I aks because Iterator gives little information so the methods can't be optimized well, what if I knew that my pseudo coll returns ordered or has fast random acces) – Aktau Feb 21 '12 at 10:45
For a method, just yield:
def odd(from: Int, to: Int): List[Int] =
for (i <- List.range(from, to) if i % 2 == 1) yield i

- 55,340
- 13
- 112
- 144
-
5Correct, but...the code example doesn't actually answer the question. Just replace both instances of "List" with "Iterator" and it works perfectly! – Todd Owen Jan 04 '15 at 06:52
These two answers had help from the posts below and thanks @Dima.
How do I implement an iterator for an existing singly linked list?
why does this iterable implementation produce a stackoverflow?
Lets assume you have a class linked list. And the requirement is to print all the elements in the list.
trait LinkedList {
def nodeValue: Int
def tailList: LinkedList
}
class Node(val nodeValue: Int, val tailList: LinkedList) extends LinkedList
object Nil extends LinkedList {
def nodeValue = throw new IllegalAccessException("head of Nil")
def tailList = throw new IllegalAccessException("tail of Nil")
}
val singleLinkedList = new Node(1,Nil)
val chainedLinkedList = new Node(2,singleLinkedList)
print(chainedLinkedList)
A$A44$A$A44$Node@7b7a2c78res0: Unit = ()
Now Lets implement iterator to this class.
trait LinkedList extends Iterator[Int]{
def nodeValue: Int
def tailList: LinkedList
}
class Node(val nodeValue: Int, val tailList: LinkedList) extends LinkedList {
var ptr: LinkedList = this
//The following two are mandatory for extending Iterator
override def hasNext: Boolean = ptr match { case Nil => false; case _=> true}
override def next(): Int = {
val result = ptr.nodeValue
ptr = ptr.tailList
result
}
}
object Nil extends LinkedList {
def nodeValue = throw new IllegalAccessException("head of Nil")
def tailList = throw new IllegalAccessException("tail of Nil")
//The following two are mandatory for extending Iterator
override def hasNext: Boolean = false
override def next(): Int = throw new IllegalAccessException("next of Nil")
}
val singleLinkedList = new Node(1,Nil)
val chainedLinkedList = new Node(2,singleLinkedList)
//Printing this first Time
chainedLinkedList.foreach(println)
//Prints 2 1
//Printing second Time
chainedLinkedList.foreach(println)
//No output
In the iterator implementation, once ptr reached the end, it could did not advance back. Iterable implementation solves this.
trait LinkedList extends Iterable[Int]{
val nodeValue: Int
val tailList: LinkedList
override def toString(): String = this.mkString(" -> ")
}
class Node(val nodeValue: Int, val tailList: LinkedList) extends LinkedList {
override def iterator: Iterator[Int] = Iterator
.iterate(this: LinkedList)(_.tailList)
.takeWhile(_ != Nil)
.map(_.nodeValue)
}
object Nil extends LinkedList {
lazy val nodeValue= throw new IllegalAccessException("head of Nil")
lazy val tailList = throw new IllegalAccessException("tail of Nil")
override def iterator: Iterator[Int] = Iterator.empty
}
val singleLinkedList = new Node(1,Nil)
val chainedLinkedList = new Node(2,singleLinkedList)
//Printing this first Time
chainedLinkedList.foreach(println)
Output 2 -> 1
chainedLinkedList.foreach(println)
Output 2 -> 1

- 1,811
- 1
- 18
- 31