RAGHHURAAMM
RAGHHURAAMM

Reputation: 1099

Why Scala 'String' object's iterator and 'List[Int]' object's iterator are behaving differently here?

I just wanted to explore the behaviors of the iterators of a String object and a List[Int] object in REPL and the tests are as shown below:

scala> val list = List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)

scala> val itL = list.iterator
itL: Iterator[Int] = non-empty iterator

scala> List(8,5,list.size-13).map(itL.take(_).mkString)
res85: List[String] = List(12345678, 910111213, 141516)

scala> val st = "abcdefghijklmnop"
st: String = abcdefghijklmnop

scala> val itS = st.iterator
itS: Iterator[Char] = non-empty iterator

scala> List(8,5,st.size-13).map(itS.take(_).mkString)
res84: List[String] = List(abcdefgh, abcde, abc)

Why the iterators are behaving differently? My expected output in String object's case is:

List[String] = List(abcdefgh, ijklm, nop)

Can somebody explain this if possible with examples.

Another Observation is: The behaviour of the iterator of the Range object is also exactly similar to String object as seen below:

scala> val x = (1 to 16)
x: scala.collection.immutable.Range.Inclusive = Range 1 to 16

scala> val t = (1 to 16).iterator
t: Iterator[Int] = non-empty iterator

scala> List(8,5,x.size-13).map(t.take(_).mkString)
res103: List[String] = List(12345678, 12345, 123)

If the Range is converted to List or Set the respective iterators are behaving exactly as per my expectation always:

scala> val x1 = (1 to 16).toList
x1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)

scala> val t1 = x1.iterator
t1: Iterator[Int] = non-empty iterator

scala> List(8,5,x1.size-13).map(t1.take(_).mkString)
res104: List[String] = List(12345678, 910111213, 141516)

scala> val x2 = (1 to 16).toSet
x2: scala.collection.immutable.Set[Int] = Set(5, 10, 14, 1, 6, 9, 13, 2, 12, 7, 3, 16, 11, 8, 4, 15)

scala> val t2 = x2.iterator
t2: Iterator[Int] = non-empty iterator

scala> List(8,5,x2.size-13).map(t2.take(_).mkString)
res105: List[String] = List(51014169132, 12731611, 8415)

Upvotes: 2

Views: 161

Answers (1)

jwvh
jwvh

Reputation: 51271

There's a note attached to the Iterator.take(n:Int) API documentation:

Reuse: After calling this method, one should discard the iterator it was called on, and use only the iterator that was returned. Using the old iterator is undefined, subject to change, and may result in changes to the new iterator as well.

It looks like you've discovered some "undefined" behavior.

Upvotes: 8

Related Questions