The intention behind the first snippet of code below is to define a new trait for iterables that provides an additional method for prepending a new element in front of the iterable.
However, when running the code in the second snippet, we see that the +:
method returns an iterable yielding an infinity of 0
s.
What am I doing wrong and how can I get the intended behavior?
Note: I added the outer
val to make sure I get the correct iterator when defining the methods of the object returned by +:
; I don't know how to get access to that iterator otherwise (Iterable2.this.iterator
did not compile).
trait Iterable2[A] extends Iterable[A] {
val outer :Iterable[A] = this
def +:(elem :A) = new Iterable2[A] {
override def iterator: Iterator[A] = new Iterator[A] {
private[this] var virgin = true
override def hasNext: Boolean = virgin || outer.iterator.hasNext
override def next(): A = {
if (virgin) {virgin = false; elem}
else outer.iterator.next()
}
}
}
}
val i = new Iterable2[Int] {
override def iterator: Iterator[Int] = Iterator(1,2,3)
}
for (j <- 0 +: i) {
println(j)
}
The first error in my original code is that
outer.iterator
returns a new iterator each time it's evaluated, as pointed out by @DiegoMartinoia and @Imm.However, it is also necessary to replace
val outer = this
withouter =>
, as suggested by @misberner.For now, this is only a partial answer to my question, as it doesn't explain why the second change is necessary.
The corrected trait code is thus: