scalakotliniterator

Iteration in Scala vs. Kotlin


I'm migrating some code from Scala to Kotlin, I observe different behaviour:

Scala:

var i = 0

Iterator.continually{
  println(s"i=$i")
  i += 1
  i
}.takeWhile { 
  _ < 3
}.foreach { i =>
  println(s"I=$i")
}

Output:

i=0
I=1
i=1
I=2
i=2

Kotlin equivalent:

fun <A> continousIterator(func: () -> A): Iterable<A> =
    object: Iterable<A> {
        override fun iterator() =
            object: Iterator<A> {
                override fun hasNext(): Boolean = true
                override fun next(): A = func()
            }
    }
    
var i = 0;
    
fun main() {
    continousIterator{
        println("i=$i")
        i += 1
        i
    }.takeWhile{
      it < 3
    }.forEach { 
      println("I=$it")
    }
}

Output:

i=0
i=1
i=2
I=1
I=2

When we have state, the result isn't the same, the calling order of func() and the iterator are different.

I wonder why.


Solution

  • In Kotlin, when takeWhile is called, takeWhile iterates through the sequence immediately and prints 0 to 2, and produces a List. Only after that does the forEach get run, printing 1 and 2.

    To replicate the Scala behaviour, you need forEach to consume the sequence, instead of takeWhile. A Sequence can do this:

    generateSequence {
        println("i=$i")
        i += 1
        i
    }.takeWhile{it < 3}.forEach { println("I=$it")}
    

    Operations on a Sequence are all lazy. They don't consume the sequence unless absolutely necessary.