You should be very careful about ever implicitly converting an Iterator
into an Iterable
(I normally use Iterator.toList
- explicitly). The reason for this is that, by passing the result into a method (or function) which expects an Iterable
, you lose control of it to the extent that your program might be broken. Here's one example:
def printTwice(itr : Iterable[String]) : Unit = {
itr.foreach(println(_))
itr.foreach(println(_))
}
If an Iterator
were somehow implicitly convertible into an Iterable
, what will the following would print?
printTwice(Iterator.single("Hello"))
It will (of course) only print Hello once. Very recently, the trait
TraversableOnce
has been added to the collections library, which unifies Iterator
and Iterable
. To my mind, this is arguably a mistake.
My personal preference is to use Iterator
explicitly wherever possible and then use List
, Set
or IndexedSeq
directly. I have found that I can rarely write a method which is genuinely agnostic of the type it is passed. One example:
def foo(trades: Iterable[Trade]) {
log.info("Processing %d trades", trades.toList.length) //hmmm, converted to a List
val shorts = trades.filter(_.side.isSellShort)
log.info("Found %d sell-short", shorts.toList.length) //hmmm, converted to a List again
//etc