Search code examples
scalapattern-matchingcase-class

What is it called when a case class constructor param is used outside the class?


What happens in line nine below that makes the result variable accessible on line ten?

The example is from the Akka documentation on testing. The Ask in line eight returns a scala.concurrent.Future. The Future.value() returns an Option[Try[T]], which will either be Some(Success(t)) or Some(Failure(error)). Then Some.get is called, which should either return the t or the error, depending the result of the Try.

It seems like whether or not the value of future.value.get is an error in line nine, it is attempting to instantiate a new Success, which is defined as a case class in Try, with the return value from Some.get. The Success on line nine is not used directly, but instead the case class constructor parameter result somehow makes it into scope so it can be used in line ten. What is this called in Scala? Where can I find out more about how this syntax works?

1.  import akka.testkit.TestActorRef
2.  import scala.concurrent.duration._
3.  import scala.concurrent.Await
4.  import akka.pattern.ask
5.  
6.  val actorRef = TestActorRef(newMyActor)
7.  // hypothetical message stimulating a '42' answer
8.  val future = actorRef ? Say42
9.  val Success( result: Int ) = future.value.get
10. result should be (42)

Solution

  • val Success( result: Int ) = future.value.get is a pattern match. You can use pattern-matching to assign values to identifiers when declaring a val. It's about the same as writing:

    val result: Int = future.value.get match {
        case Success(r: Int) => r
    }
    

    Notice how this is not an exhaustive match, though, and if future.value.get is a Failure, then a MatchError will be thrown. In the context of unit tests, I use pattern matching like this all the time, since a MatchError would be another indication of failure.

    Here are a few examples of similar (safer) pattern-matching assignments:

     val (a, b) = (1, 2)
    
     case class Test(i: Int, j: String)
     val test = Test(1, "a")
     val (i, j) = test
    
     val list = List(1, 2, 3, 4)
     val List(first, second, _*) = list // though this will fail if the List has less than 3 elements