scalaakkavalue-class

Matching against Value Classes in Akka


I've created the Value Class

final class Feature(val value: Vector[Double]) extends AnyVal

To match against that class in scala:

val d = new Feature(Vector(1.1))
s match {
  case a:Feature => println(s"a:feature, $a")
  case _ => println("_")
}

This works correctly, but in Akka, with the same class above, in the receive method this is not working:

  def receive = LoggingReceive {
    case a:Feature =>
      log.info("Got Feature: {}", a)
    case _ => println("_")
  }

When I execute the code, although I am sending a Feature, the case statement that is being executed is case _ => println("_"), but, If I change the code to this:

  def receive = LoggingReceive {
    case a:Feature =>
      log.info("Got Feature: {}", a)
    case b:Vector[_] =>
      log.info("GOT FEATURE")
    case _ => println("_")
  }

case b:Vector[_] is executed.

Akka documentation mentions:

The recommended way to instantiate actor props uses reflection at runtime to determine the correct actor construc- tor to be invoked and due to technical limitations is not supported when said constructor takes arguments that are value classes. In these cases you should either unpack the arguments or create the props by calling the constructor manually:

But do not mention nothing about matching against Value classes

Update

Thanks to YuvalItzchakov for the help. The Actor's code is as below:

Actor that receive the message:

  def receive = LoggingReceive {
    case Feature(a) =>
      log.info("Got feature {}", a)
    // ....
  }

Actor sending the message:

  def receive = LoggingReceive {
    // ..
    case json: JValue =>
      log.info("Getting json response, computing features...")
      val features = Feature(FeatureExtractor.getFeatures(json))
      log.debug(s"Features: $features")
      featureListener.get ! features
    // ..
  }

Solution

  • Due to the nature of how value classes work, both your examples will cause the allocation of Feature. Once due to run-time checking in your pattern matching example, and the other due to the signature of receive which requires Any as the input type.

    As the docs for Value Classes specify (emphasis mine):

    Allocation Summary

    A value class is actually instantiated when:

    • a value class is treated as another type.
    • a value class is assigned to an array.
    • doing runtime type tests, such as pattern matching.

    This means that if you're seeing a Vector[_] type, that means your actually passing a concrete vector from some place in the code.