Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there a difference in behavior between these two pattern matches in a for comprehension?

Tags:

scala

Consider this Map[String, Any]:

val m1 = Map(("k1" -> "v1"), ("k2" -> 10))

Now let's write a for:

scala> for ((a, b) <- m1) println(a + b)
k1v1
k210

So far so good.

Now let's specify the type of the second member:

scala> for ((a, b: String) <- m1) println(a + b)
k1v1

scala> for ((a, b: Integer) <- m1) println(a + b)
k210

Here, as I specify a type, filtering takes place, which is great.

Now say I want to use an Array[Any] instead:

val l1 = Array("a", 2)

Here, things break:

scala> for (v: String <- l1) println(v)
<console>:7: error: type mismatch;
 found   : (String) => Unit
 required: (Any) => ?

My double question is:

  • why doesn't the second match filter as well?
  • is there a way to express such filtering in the second scenario without using a dirty isInstanceOf?
like image 431
ebruchez Avatar asked Nov 29 '22 04:11

ebruchez


2 Answers

The main reason for the speced behavior is that we want to encourage people to add type annotations, for clarity. If in for comprehensions, they get potentially very costly filter operations instead, that's a trap we want to avoid. However, I agree that we should make it easier to specify that something is a pattern. Probably a single pair of parens should suffice.

val x: String = y       // type check, can fail at compile time
val (x: String) = y     // pattern match, can fail at run time

for (x: String <- ys)   // type check, can fail at compile time
for ((x: String) <- ys) // pattern match, can filter at run time
like image 27
Martin Odersky Avatar answered Dec 05 '22 11:12

Martin Odersky


Well, the latter example doesn't work because it isn't spec'ed to. There's some discussion as to what would be the reasonable behavior. Personally, I'd expect it to work just like you. The thing is that:

val v: String = (10: Any) // is a compile error
(10: Any) match {
    case v: String =>
} // throws an exception

If you are not convinced by this, join the club. :-) Here's a workaround:

for (va @ (v: String) <- l1) println(v)

Note that in Scala 3, you can:

for (case v: String <- l1) println(v)
like image 195
Daniel C. Sobral Avatar answered Dec 05 '22 10:12

Daniel C. Sobral