Reputation: 75
In the Scala shell I did this:
import java.util._
import scala.collection.JavaConversions._
val t: SortedMap[String,Int] = new TreeMap[String,Int] () // produces an empty java.util.SortedMap
t("a") = 1; t("b") = 2; t("A") = 3; t("0") = 4
t // prints: res35: java.util.SortedMap[String,Int] = {0=4, A=3, a=1, b=2}, as expected
t foreach println // also prints the (k,v) pairs in the same TreeMap sorted order
However, the following statement does not print the pairs in sorted order, it appears to print them in hash bucket order, (0,4) (b,2) (A,3) (a,1):
for ((k,v) <- t) printf("(%s,%d)%n", k, v)
In other answers related to for and foreach it seems that a for comprehension is supposed to translate into a use of foreach like so:
"A for-comprehension for (p <- e) e0 is translated to e.foreach { case p => e0 }"
but that does not seem to be what is happening here.
Note that if I create a scala SortedMap from a scala TreeMap that both the foreach and the for produce the (k,v) pairs in sorted order as I expected. It seems like some way that the Java TreeMap is being converted for scala is different.
Any comments or ideas about why this discrepancy?
Upvotes: 4
Views: 1980
Reputation: 297305
Well, p
and (k,v)
are not the same thing. Your for-comprehension is translated thus:
t.filter{
case (k, v) => true
case _ => false
}.map {
case (k, v) => printf("(%s,%d)$n")
}
Once filter
puts it's hands on the java collection, it becomes a Scala collection, and is no longer sorted.
As a side note, on Scala 2.10 the above is no longer true since it detects that there's no element that isn't a (k,v) from the static type at compile time, and doesn't generate the filter. Here:
scala> for ((k,v) <- t) printf("(%s,%d)%n", k, v)
<console>:15: warning: dead code following this construct
for ((k,v) <- t) printf("(%s,%d)%n", k, v)
^
(0,4)
(A,3)
(a,1)
(b,2)
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> reify{for ((k,v) <- t) printf("(%s,%d)%n", k, v)}
res4: reflect.runtime.universe.Expr[Unit] =
Expr[Unit](scala.collection.JavaConversions.mapAsScalaMap(t).foreach(((x$1) => x$1: @unchecked match {
case scala.Tuple2((k @ _), (v @ _)) => scala.this.Predef.printf("(%s,%d)%n", k, v)
})))
PS: Prefer JavaConverters
over JavaConversions
.
Upvotes: 7