13

Does Scala provide a built-in class, utility, syntax, or other mechanism for converting (by wrapping) an Iterator with an Iterable?

For example, I have an Iterator[Foo] and I need an Iterable[Foo], so currently I am:

 val foo1: Iterator[Foo] = ....
 val foo2: Iterable[Foo] = new Iterable[Foo] {
   def elements = foo1
 }

This seems ugly and unnecessary. What's a better way?

Eugene Yokota
  • 94,654
  • 45
  • 215
  • 319
Landon Kuhn
  • 76,451
  • 45
  • 104
  • 130

2 Answers2

14

Iterator has a toIterable method in Scala 2.8.0, but not in 2.7.7 or earlier. It's not implicit, but you could define your own implicit conversion if you need one.

Jay Conrod
  • 28,943
  • 19
  • 98
  • 110
8

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
oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
  • 4
    I -1'd you because your statement "It will (of course) only print Hello once" is false. Scala's `toIterable` wraps the Iterator in a Stream, which ensures that you get the proper multiple iteration semantics. This makes much of your answer incorrect. – Urban Vagabond Sep 26 '12 at 20:38