54

given:

val m = Map[String, Int]("a" -> 1, "b" -> 2, "c" -> 3)
m.foreach((key: String, value: Int) => println(">>> key=" + key + ", value=" + value))

why does the compiler complain

error: type mismatch
found   : (String, Int) => Unit
required: (String, Int) => ?
Dzhu
  • 4,311
  • 5
  • 36
  • 48

7 Answers7

81

I'm not sure about the error, but you can achieve what you want as follows:

m.foreach(p => println(">>> key=" + p._1 + ", value=" + p._2))

That is, foreach takes a function that takes a pair and returns Unit, not a function that takes two arguments: here, p has type (String, Int).

Another way to write it is:

m.foreach { case (key, value) => println(">>> key=" + key + ", value=" + value) }

In this case, the { case ... } block is a partial function.

Philippe
  • 9,582
  • 4
  • 39
  • 59
  • that's nice, more in line with dynamic language obj.each {k,v => ...} approach and more readable than tuple ._1, ._2 syntax – virtualeyes Dec 23 '11 at 14:00
  • Juts curious, is there any performance consideration for second usage(case)? For each element try to 'case' them assign to variable etc. I want my code readable but also to fast as possible as. – endertunc Dec 14 '15 at 10:01
36

oops, read the doco wrong, map.foreach expects a function literal with a tuple argument!

so

m.foreach((e: (String, Int)) => println(e._1 + "=" + e._2))

works

Dzhu
  • 4,311
  • 5
  • 36
  • 48
18

You need to patter-match on the Tuple2 argument to assign variables to its subparts key, value. You can do with very few changes:

m.foreach{ case (key: String, value: Int) => println(">>> key=" + key + ", value=" + value)} 
Francois G
  • 11,957
  • 54
  • 59
14

The confusing error message is a compiler bug, which should be fixed in 2.9.2:

Paul Butcher
  • 10,722
  • 3
  • 40
  • 44
  • I've just checked (by compiling https://github.com/paulbutcher/baderrormessage against both 2.9.1 and 2.9.2). I can see the problem in 2.9.1 and not in 2.9.2. If you have an example of the problem still occurring, perhaps you should reopen the bug? – Paul Butcher Jan 14 '13 at 22:35
  • I have just tried the code posted in the answer by @(Eishay Smith) below (I believe is the exact same problem as shown in the question) with Scala 2.9.2 (Java HotSpot 1.7.0 VM for Windows 64-bit ) and can see the same absurd message shown in his post. – Renato Jan 14 '13 at 22:42
  • Here is what happens when I compile your code from Git: Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0). Type in expressions to have them evaluated. Type :help for more information. scala> class Foo extends Function2[Int, Int, Int] { | def apply(x: Int, y: Int) = x + y | override def tupled: (Int, Int) => Int = super.tupled | } :9: error: type mismatch; found : ((Int, Int)) => Int required: (Int, Int) => Int override def tupled: (Int, Int) => Int = super.tupled ^ – Renato Jan 14 '13 at 22:47
  • 1
    That error message is correct. Note that there are two sets of parentheses in the "found" line. The bug was that it used to print only a single set of parentheses. If you try it in 2.9.1 and diff the output, you will see that they are different. – Paul Butcher Jan 14 '13 at 23:02
5

Excellent question! Even when explicitly typing the foreach method, it still gives that very unclear compile error. There are ways around it, but I can't understand why this example does not work.

scala> m.foreach[Unit] {(key: String, value: Int) => println(">>> key=" + key + ", value=" + value)}
<console>:16: error: type mismatch;
 found   : (String, Int) => Unit
 required: (String, Int) => Unit
              m.foreach[Unit] {(key: String, value: Int) => println(">>> key=" + key + ", value=" + value)}
                                                         ^
Eishay Smith
  • 1,137
  • 9
  • 13
1

Docs says argument is tuple -> unit, so We can easily do this

Map(1 -> 1, 2 -> 2).foreach(tuple => println(tuple._1 +" " + tuple._2)))
vikashait
  • 499
  • 4
  • 10
0

Yet another way:

Map(1 -> 1, 2 -> 2).foreach(((x: Int, y: Int) => ???).tupled)

However it requires explicit type annotations, so I prefer partial functions.

Yaroslav
  • 4,543
  • 5
  • 26
  • 36