Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this Iterator infinitely loop?

I'm attempting to chain Iterators:

var it = Iterator(1)
it.next
it = Iterator(2) ++ it
it.next
it.hasNext

This infinitely loops on the hasNext as you can see here: https://scastie.scala-lang.org/qbHIVfsFSNO5OYmT4pkutA

If you run this and inspect the stack while it's infinitely looping, it's looping in the concetentation:

        at scala.collection.Iterator$ConcatIterator.merge(Iterator.scala:213)
        at scala.collection.Iterator$ConcatIterator.advance(Iterator.scala:197)
        at scala.collection.Iterator$ConcatIterator.hasNext(Iterator.scala:227)

(This stack is from Scala 2.12.11, but the Scastie link shows same behavior in 2.13.2).

I know that one should never use an iterator after calling a method on it, but this appears like it would work to me. Using the var to point to the "current" Iterator and changing it to point to a new Iterator that appends the remainder of the previous one.

The following slight modification does work:

var it = Iterator(1)
it.next
val x = it
it = Iterator(2) ++ x
it.next
it.hasNext

Scastie link: https://scastie.scala-lang.org/1X0jslb8T3WIFLHamspYAg

This suggests to me that somehow the broken version is creating an Iterator that is appending itself. Any hints as to what is going on here?

like image 569
Jack Koenig Avatar asked May 15 '20 22:05

Jack Koenig


People also ask

Why is my for loop running infinitely?

An infinite loop occurs when a condition always evaluates to true. Usually, this is an error. For example, you might have a loop that decrements until it reaches 0.

How do I get out of endless loop?

In order to come out of the infinite loop, we can use the break statement. Let's understand through an example. In the above code, we have defined the while loop, which will execute an infinite number of times until we press the key 'n'. We have added the 'if' statement inside the while loop.

What causes an infinite loop error in a while statement?

Infinite loops An infinite loop is one that starts and never stops. This happens when the true/false expression never returns a false value. While there can be some cases where you might want this to happen, most often an infinite loop is the result of a bug in your program's logic.

Why iterator is used instead of for loop?

In for-each loop, we can't modify collection, it will throw a ConcurrentModificationException on the other hand with iterator we can modify collection. Modifying a collection simply means removing an element or changing content of an item stored in the collection.


1 Answers

The argument to the ++ method of Iterator is passed by name. ++ returns a new Iterator that just stores a function which returns it, but doesn't call it until you try to use the appended elements.

So ++ tries to evaluate the argument only when you call it.hasNext, but by that time it is already redefined as the result of ++, so it ends up trying to append it to itself.

In other words vars and by-name parameters don't work together.

So don't reassign Iterator method results to the same variable and give them new names instead:

val it = Iterator(1)
it.next
val it2 = Iterator(2) ++ it
it2.next
it2.hasNext
like image 124
Kolmar Avatar answered Sep 25 '22 03:09

Kolmar