What is special about case classes in Akka?

608 views Asked by At

I have read that case classes can be used with pattern matching. But, I am able to use a regular class with pattern matching as well. This question gives a regular scala perspective. I want it both from scala as well as akka perspective for this specific code. For example:

Actor class:

class TestActor extends Actor {

  def receive={
    case One(num)=>println("One "+num)
    case t:Two=>println("Two "+t.num)
    case _=>println("Another")
  }
}

object TestActor{
  case class One(num:Int)
}

Class Two:

class Two(var num:Int){  }

Main:

object Main2 extends App{

  val system=ActorSystem("t")
  val testActor=system.actorOf(Props[TestActor],"test")

  val t=new Two(200)
  val o=TestActor.One(100)

  testActor!o
  testActor!t

}

Output is:

One 100
Two 200

I know I am missing something here, probably in my understanding of pattern matching. Can someone help me out?

1

There are 1 answers

0
Yuval Itzchakov On BEST ANSWER

As you've noticed, the main difference with case classes in Akka is the ability to use their extractors (unapply methods) when matching (other than the usual features you get our of case classes, such as an implementation for hashCode, equals, and working with them as a product type).

With a larger example, you can see how this plays out nice. For example, assume you're using Akka-HTTP client to make HTTP requests to a third party service, and you want to operate differently if you get a StatusCode.OK, or any other status code. Because HttpResponse provides an unapply method, you can do:

case HttpResponse(StatusCodes.OK, _, entity, _)) => // We're good, parse the data.
case HttpResponse(statusCode, _, _, _)) => // Operate on status code != OK

Instead of:

case response: HttpResponse =>
  if (response.statusCode != StatusCodes.OK) {
    // Stuff
  }
  else {
    // Other stuff
  }

When your logic becomes more complex, extracting only the values you want can be very helpful and less verbose. In our codebase we have something more complex with multiple values, something like:

case (Foo(bar, baz), resp@HttpResponse(statusCode, _, _, _))

Of course, you can always create an unapply method in a companion object yourself and get the same semantics of a case class yourself, but you usually don't want to be writing that boilerplate, allowing the compiler to do it for you.

To sum up, using case class as your data container in Akka eases the work with pattern matching, which is often what you do when implementing a receive method.