A common mistake in scala is using Unit, the companion object, as its value. The correct value of type Unit is (). Typically, one can get away with using Unit as the value, and

def unitType: Unit = Unit

def unitValue: Unit = ()

behave similarly. However, this becomes an issue when serialization1 comes into play. Take, for example, the following actor2:

class UnitActor extends Actor {
  override def receive: Receive = {
    case Unit => sender ! "Received Unit Object"
    case () => sender ! "Received Unit value"
  }
}

This simply returns a string to the sender upon receipt of a message. When run on the same VM, everything behaves as expected:

class NoSerializableTest extends TestKit(ActorSystem("SerializableTest")) with WordSpecLike with ImplicitSender {

  "ActorSystem without requiring serialization" should {
    val unitActor = TestActorRef[UnitActor]

    "send Unit object" in {
      unitActor ! Unit
      within(1 second){
        expectMsg("Received Unit Object")
      }
    }
    "send unit value" in {
      unitActor ! ()
      within(1 second){
        expectMsg("Received Unit value")
      }
    }
  }
}

However, if the same actor was used in a distributed system, messages would have to be serialized and Unit messages will not be sent across the wire.

class SerializableTest extends TestKit(ActorSystem("SerializableTest", ConfigFactory.parseString(
  "akka.actor.serialize-messages = on"))) with WordSpecLike with ImplicitSender {

  "ActorSystem with serialization" should {
    val unitActor = TestActorRef[UnitActor]

    "fail to send Unit Object" in {
      unitActor ! Unit
      within(1 second){
        expectNoMsg()
      }
    }
    "send unit value" in {
      unitActor ! ()
      within(1 second){
        expectMsg("Received Unit value")
      }
    }
  }
}

Note that we have mimicked what would happen when messages are sent between VMs by setting akka.actor.serialize-messages = on3. Using the default java serializer, () messages are sent without a problem, but Unit messages are dropped with the following error being logged to STDOUT:

[ERROR] [05/17/2015 14:37:30.959] [pool-6-thread-3-ScalaTest-running-SerializableTest] [akka://SerializableTest/user/$$a] swallowing exception during message send
java.io.NotSerializableException: No configured serialization-bindings for class [scala.Unit$]

Unit is just a regular companion object and plain objects are not serializable, only case objects are.

Take aways:

  • Use () as the Unit value and not Unit itself.
  • Turn on serialize-messages when testing actor systems that will leave a single VM.
  1. Using the default java serializer. Other serializers’ behavior is left as an exercise to the reader. 

  2. Code for tests can be found https://github.com/frosforever/akka-unit-messages 

  3. http://doc.akka.io/docs/akka/snapshot/scala/serialization.html#Verification