Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are case objects serializable and case classes not?

I am playing with this example http://scala.sygneca.com/code/remoteactors to learn how remote actors work in Scala (2.8.0). In particular I slightly modified how the messages send by the actors are defined as it follows:

sealed trait Event extends Serializable
case object Ping extends Event
case object Pong extends Event
case object Quit extends Event

and everything works as expected. Unfortunately if I define the events as case classes instead of case objects as in:

sealed trait Event extends Serializable
case class Ping extends Event
case class Pong extends Event
case class Quit extends Event

my example stop working. In more detail it seems that while case objects are serializable, case classes aren't. Indeed when I try to run my example with this last modification I get the following exception:

scala.actors.remote.DelegateActor@148cc8c: caught java.io.NotSerializableException: scalachat.remote.Ping$
java.io.NotSerializableException: scalachat.remote.Ping$
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
    at scala.actors.remote.JavaSerializer.serialize(JavaSerializer.scala:46)
    at scala.actors.remote.NetKernel.namedSend(NetKernel.scala:38)
    at scala.actors.remote.NetKernel.forward(NetKernel.scala:71)
    at scala.actors.remote.DelegateActor$$anonfun$act$1$$anonfun$apply$1.apply(Proxy.scala:182)
    at scala.actors.remote.DelegateActor$$anonfun$act$1$$anonfun$apply$1.apply(Proxy.scala:123)
    at scala.actors.ReactorTask.run(ReactorTask.scala:34)
    at scala.actors.ReactorTask.compute(ReactorTask.scala:66)
    at scala.concurrent.forkjoin.RecursiveAction.exec(RecursiveAction.java:147)
    at scala.concurrent.forkjoin.ForkJoinTask.quietlyExec(ForkJoinTask.java:422)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.mainLoop(ForkJoinWorkerThread.java:340)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:325)

Is there a reason why case objects can be made serializable and case classes can't? Is there a way to make my example working with case classes either?

Edit: as suggested by Victor and confirmed by Aaron I am sending the companion object as message instead of the class. Moreover inspecting the compiled code with javap it appears evident that while the class is serializable:

public class scalachat.remote.Ping extends java.lang.Object implements scalachat.remote.Event,java.io.Serializable,scala.ScalaObject,scala.Product

the companion object is not:

public final class scalachat.remote.Ping$ extends scala.runtime.AbstractFunction0 implements scala.ScalaObject

Now the question is: how can I specify that I want to use the class instead of the companion object? I also added an empty couple of parenthesis when I send the message as suggested by Aaron like in:

pong ! Ping()

but nothing is changed. In the end I also added a fake parameter to the case class

case class Ping(i: Int) extends Event

sending the message as:

pong ! Ping(0)

but without experiencing any difference still. Any suggestion?

like image 460
Mario Fusco Avatar asked Nov 01 '10 09:11

Mario Fusco


People also ask

Are Case classes Serializable?

All case classes automatically extend Product and Serializable .

Why does a class need to be Serializable?

Serializable is a marker interface (contains no methods) that tell the Java Virtual Machine (JVM) that the objects of this class is ready for being written to and read from a persistent storage or over the network.

What happens if object is not serialized?

What happens if you try to send non-serialized Object over network? When traversing a graph, an object may be encountered that does not support the Serializable interface. In this case the NotSerializableException will be thrown and will identify the class of the non-serializable object.

What happens if the object to be serialized?

To serialize an object means to convert its state to a byte stream so way that the byte stream can be reverted back into a copy of the object. A Java object is serializable if its class or any of its superclasses implements either the java.


2 Answers

@serializable case class Foo

I was also surprised that case objects were serializable per default.

Edit: After reading the exception properly I suspect that:

You're trying to send the generated companion object of the case class over the wire, instead of an instance of the case class.

like image 109
Viktor Klang Avatar answered Oct 06 '22 17:10

Viktor Klang


Case classes without parameters are meaningless and deprecated. And I see no Serializable in Scala, just serializable. Does it work if you fix these things?

like image 34
Daniel C. Sobral Avatar answered Oct 06 '22 16:10

Daniel C. Sobral