Question

Currently my code needs class casting

val dataWriter: BytesDataWriter = createDataWriter

 def createDataWriter(p: SomeClass) =
    p.create_datawriter().asInstanceOf[BytesDataWriter]

The create_datawriter method will return the superclass DataWriter. Instead of casting it using asInstanceOf, I tried this approach

val dataWriter: BytesDataWriter = createDataWriter(p)  match {
      case writer: BytesDataWriter => writer
      case _ => throw new ClassCastException
    }

This is too verbose, and in case case does not work. Is there a better alternative to class casting?

Was it helpful?

Solution

You would use the second approach in case you can do something with a non-BytesDataWriter result, or to get a better error message:

val dataWriter: BytesDataWriter = p.create_datawriter() match {
  case writer: BytesDataWriter => writer
  case other => throw new Exception(s"Expected p to create a BytesDataWriter, but got a ${other.getClass.getSimpleName} instead!")
}

Otherwise, use asInstanceOf.

OTHER TIPS

The answer from Alexey Romanov is a good advice for your specific situation. Alternatively you could try to avoid this situation by changing the sctructure of the surrounding code.

Can your problem be reformulated?

When you are using a class and instantiate it, it looks like you are implementing some kind of configurable dependency handling. This is a complex problem, but fortunately there are some good solutions for this:

Dependency injection

You could use some kind of dependency injection and inject the needed ByteDataWriter with the specialized type. Look at the "Robot Leg" example described in the Google Guice FAQ on how to deal with different variants of the same base class, and on how to deal with generics. This might help you to avoid your problem with DataWriter and ByteDataWriter.

Duck typing

You can also access your DataWriter with a protocol (or in Scala speak: a strucutral type). Structural typs will not be checked at compile time, so no need for a class cast.

Cake pattern

Or you can handle you dependencies using a Scala specialty: The cake pattern. With this pattern you can compose your class just as needed. You can design the class needing the ByteDataWriter completely type safe. The compiler will then make sure, that it can only combined with the correct class. No need for a class cast. The disadvantage is, that you cannot reconfigure the dependencies using a config file. But usually this is not necessary, because the supported variants are well known at compile time.

Conclusion: Try to reformulate when possible

If you have the option, consider to re-design your code using one of the methods described above, to get rid of the class cast. It is very likely that you will have the same problem on many other places in your code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top