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?
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.
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.
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.
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.
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 var
s 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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With