Question

I have the following class definition:

class Foo[T](iteratorThunk: () => Iterator[T]) {
  def values = iteratorThunk()
}

And I would like Foo to have all the methods that Iterator exposes, while still returning objects of type Foo. For instance, I would like to be able to do:

val a = new Foo({ () => List(1, 2, 3).toIterator })
val b = new Foo({ () => List(4, 5, 6).toIterator })
val c = a ++ b

And have c equal to:

new Foo({ () => a.values ++ b.values })

I had a look at forwarders (IterableForwarder, TraversableForwarder, ...), but none seemed fit to forward methods to an Iterator, and I would still like to keep Foo as both the static and dynamic result type.

What is the best way to achieve this behavior, without defining every forwarding method?

Was it helpful?

Solution

I need the Foo class as it is, and not only as an Iterator because I need to be able to do more than one pass through its values.

Then you want either a Traverable or an Iterable. To have them work as you wish, you need to extend both them and TraversableLike or IterableLike, through which you'll specify the return type. And you'll need to provide both a Builder and a CanBuildFrom as well.

Here's a simple implementation:

import scala.collection.IterableLike
import scala.collection.mutable.LazyBuilder
class Foo[T](iteratorThunk: () => Iterator[T]) extends Iterable[T] with IterableLike[T, Foo[T]] {
  def iterator = iteratorThunk()
  override protected def newBuilder = new Foo.FooBuilder[T]
}

object Foo {
  class FooBuilder[T] extends LazyBuilder[T, Foo[T]] {
    def result(): Foo[T] = {
      val coll = parts.toList.flatten
      new Foo(() => coll.iterator)
    }
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top