I was working through Odersky's ScalaDays 2011 keynote talk, where he constructs a phone number synonym generator in remarkably few lines of code, when I got to this particular line (assigning charCode ):

val mnem: Map[Char, String] = // phone digits to mnemonic chars (e.g. '2' -> "ABC") val charCode: Map[Char, Char] = for ((digit, str) <- mnem; letter <- str) yield (letter -> digit) // gives ('A', '2'), ('B', '2') etc

Why is charCode of type Map ?

When I yield tuples in other examples, I merely obtain a sequence of tuples -- not a map. For example:

scala> for (i <- 1 to 3) yield (i -> (i+1)) res16: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((1,2), (2,3), (3,4))

One can easily convert that to a map with toMap() , like so...

scala> (for (i <- 1 to 3) yield (i -> (i+1))).toMap res17: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 2 -> 3, 3 -> 4)

... but somehow, Odersky's example avoids this.

What Scala magic, if any, am I overlooking here?

Addendum 1: Implicit conversion? I'd like to add some detail pertaining to Oxbow Lake's comment (NB: my comment there may be partially in error, having misunderstood slightly, perhaps, what he was getting at).

I suspected that some kind of implicit conversion was happening because a map was required. So I tried Odersky's iterator in the interpreter, with no hints as to what it should produce:

scala> val mnem = Map('2' -> "ABC", '3' -> "DEF", '4' -> "GHI") // leaving as a map, still scala> for ((digit, str) <- mnem; letter <- str) yield (letter, digit) res18: scala.collection.immutable.Map[Char,Char] = Map(E -> 3, F -> 3, A -> 2, I -> 4, G -> 4, B -> 2, C -> 2, H -> 4, D -> 3)

(Note that I'm leaving mnem as a map here.)

Likewise, telling the compiler I wanted a map didn't change my own result:

scala> val x: Map[Int,Int] = for (i <- 1 to 3) yield (i -> (i+1)) <console>:7: error: type mismatch; found : scala.collection.immutable.IndexedSeq[(Int, Int)] required: Map[Int,Int] val x: Map[Int,Int] = for (i <- 1 to 3) yield (i -> (i+1))

On the other hand, following Eastsun's hints (and this seems to be what OL was saying, too), the following (dorky) modification does produce a map:

scala> for ((i,j) <- Map(1 -> 2, 2 -> 2)) yield (i -> (i+1)) res20: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 2 -> 3)

So if the iterated value comes from a map, somehow a map is produced?

I expect the answer is to be understood by (a) converting the "for" loop to its longhand equivalents (a call/calls to map ) and (b) understanding what implicits are being magically invoked.

Addendum 2: Uniform Return Type: (huynhjl:) That seems to be it. My first example converts to

(1 to 3).map(i => (i, i+1)) // IndexedSeq[(Int, Int)]

Whereas the second becomes something akin to this:

Map(1 -> 2, 2 -> 2).map(i => (i._1, i._1+1)) // Map[Int,Int]

The type of "Map.map" is, then

def map [B, That] (f: ((A, B)) ⇒ B)(implicit bf: CanBuildFrom[Map[A, B], B, That]): That

Ah, trivial. ;-)

Addendum 3: Well, okay, that was too simple, still. Miles Sabin provides a/the more correct desugaring, below. Even more trivial. ;-)