Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterator.continually: cannot evaluate expression in Scala REPL

Tags:

scala

Does anyone have any idea/explanation why REPL is stuck during evaluation of last expression? The weird thing is that it does not throw any exception or anything, just nothing happens.

Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_40).

scala> val empty = Seq.empty[Int].iterator
empty: Iterator[Int] = empty iterator

scala> val emptyInfiniteIterator = Iterator.continually(empty).flatten

Thanks in advance for any explanation.

like image 937
tkachuko Avatar asked Apr 24 '16 00:04

tkachuko


1 Answers

Here is what happens. When you define iterator in Scala REPL, some information about that iterator is printed, whether it's empty or not in particular:

scala> Iterator.continually(List(1)).flatten
res1: Iterator[Int] = non-empty iterator

This information is returned by toString method of Iterator, which is defined like this:

override def toString = (if (hasNext) "non-empty" else "empty")+" iterator"

Basically, hasNext is called on newly created iterator. Now let's see what hasNext does in your case (scala.collection.TraversableOnce.FlattenOps#flatten):

  class FlattenOps[A](travs: TraversableOnce[TraversableOnce[A]]) {
    def flatten: Iterator[A] = new AbstractIterator[A] {
      val its = travs.toIterator
      private var it: Iterator[A] = Iterator.empty
      def hasNext: Boolean = it.hasNext || its.hasNext && { it = its.next().toIterator; hasNext }
      def next(): A = if (hasNext) it.next() else Iterator.empty.next()
    }
  }

Aha! hasNext recursively traverses the iterator trying to find either an end or single non-empty element. Which, in your case, never happens, as you have infinite iterator of empty elements. So, you have infinite loop which is triggered by REPL. You don't get StackOverflow, because tail recursion is used and in scala it's transpiled to while loop.

like image 115
Aivean Avatar answered Sep 28 '22 09:09

Aivean