Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala - Match Tuple of Options

I have:

val foo = Some(List(1, 2, 3)) -> Some("y")

I would like to cast match it:

foo match {
    case (Some(x), Some(y)) => println(x + " " + y)
    case _ => println("error")

This works fine for Some(List(1, 2, 3) -> Some("score")) but fails for Some(List(1, 2, 3) -> None, None -> Some("y") or None -> None with:

error: constructor cannot be instantiated to expected type;
     found   : Some[A]
     required: None.type
error: not found: value ...

Why is that?

Of course I could use getOrElse() but that does not look so elegant.

Thx a lot, Karsten

Update:

foo match {
 case (x: Some[List[Int]], y: Some[Int]) => println(x.get)
 case _ => println("error")
}

Fails as well with:

error: pattern type is incompatible with expected type;
 found   : Some[Int]
 required: None.type

I would think that case _ would take care of that.

like image 361
Karsten Avatar asked Jan 16 '14 15:01

Karsten


1 Answers

It is the compiler telling you something. If you have an expression like

val foo = Some(List(1, 2, 3)) -> None

It will have the type (Some[List[Int]], None.type), which you can easily see from typing in the expression in the scala console

scala> val foo = Some(List(1, 2, 3)) -> None
foo: (Some[List[Int]], None.type) = (Some(List(1, 2, 3)),None)

So you know at compile time that the second element of the tuple can only ever be None, a match with Some can never succeed. Hence the error message.

If you give foo a less restrictive type it will work.

val foo : (Option[List[Int]], Option[String]) = Some(List(1, 2, 3) -> None

Note that this is exactly as it should be. Matching on something that can never happen is almost definitely an error. You have to upcast to any to avoid the compile time error (but then you will get a runtime error.

like image 176
Rüdiger Klaehn Avatar answered Sep 26 '22 22:09

Rüdiger Klaehn