Domenic
Domenic

Reputation: 112857

Scala + Akka: pattern matching on type?

We have code like this scattered throughout our code base:

def receive: Receive = {
  case x: TypeX => doXishThingsWith(x)
  case y: TypeY => doYishThingsWith(y)
  case z: TypeZ => doZishThingsWith(z)
}

I find the need to give names to x, y and z kind of dumb and confusing.

I was wondering if something like this would work?

def receive: Receive = {
  case TypeX => doXishThingsWith(_)
  case TypeY => doYishThingsWith(_)
  case TypeZ => doZishThingsWith(_)
}

I have no idea if _ actually works this way. But maybe there is something similar?

Upvotes: 2

Views: 778

Answers (2)

Arne
Arne

Reputation: 8481

you can do classical polymorphism:

trait T{
    def doThings()
}

class TypeX extends T{
    override def doThings() {
        println("doXishThingsWith")
    }
}

class TypeY extends T{
    override def do Things() {
        println("doYishThingsWith")
    }
}

def receive: Receive = {
  case x: T => x.doThings()
}

using underscore in pattern matching just means throw that value away and do not make it accessible from any variable

Upvotes: 2

senia
senia

Reputation: 38045

No. case a: A => m(a) is the shortest solution.

With case TypeX you are trying to match on companion object of TypeX, so you have to use underscore or variable name: case _: TypeX.

With case _: TypeX you have no access to variable.

Workaround

Actually you could use methods without variable names using some magic like this:

def receive: Receive = (
  pf[TypeX](doXishThingsWith) orElse
  pf[TypeY](doYishThingsWith) orElse
  pf[TypeZ](doZishThingsWith)
)

You have to create method pf like this:

import reflect.{ClassTag, classTag}

def pf[T: ClassTag](f: T => _): PartialFunction[Any, Unit] = {
  case e if classTag[T].runtimeClass.isInstance(e) => f(e.asInstanceOf[T])
}

Example:

class A; class B; class C

def mA(a: A) = println(s"mA!")
def mB(b: B) = println(s"mB!")

val receive = pf(mA) orElse pf(mB)

scala> receive.lift(new A)
mA!
res0: Option[Unit] = Some(())

scala> receive.lift(new B)
mB!
res1: Option[Unit] = Some(())

scala> receive.lift(new C)
res2: Option[Unit] = None

Upvotes: 6

Related Questions