How to avoid using asInstanceOf in Scala
Currently my code requires a class
val dataWriter: BytesDataWriter = createDataWriter
def createDataWriter(p: SomeClass) =
p.create_datawriter().asInstanceOf[BytesDataWriter]
The method create_datawriter
will return the superclass DataWriter. Instead of using it with asInstanceOf
, I tried this approach
val dataWriter: BytesDataWriter = createDataWriter(p) match {
case writer: BytesDataWriter => writer
case _ => throw new ClassCastException
}
It's too verbose and in case things don't work. Is there a better alternative to class?
source to share
You would use the second approach if you can do something about the result not BytesDataWriter
or 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
.
source to share
The answer from Alexey Romanov is good advice for your specific situation. Alternatively, you can try to avoid this situation by changing the structure of the outer code.
Could your problem be reformulated?
When you use the class and instantiate it, it looks like you are implementing some kind of configuration handling for dependencies. This is a tricky problem, but luckily there are some good solutions for this:
Including dependencies
You can use some kind of dependency injection and inject as needed ByteDataWriter
with a special type. Check out the Robot Foot example described in the Google Guice FAQ for how to deal with different variants of the same base class, and how to deal with generics . This can help you avoid problems with DataWriter
and ByteDataWriter
.
Duck seal
You can also access yours DataWriter
using a protocol (or in Scala say: structured type ). Structural types will not be checked at compile time, so there is no need for cool casting.
Pie drawing
Or, you can handle your dependencies with a Scala specialty: the cake pattern . With this template, you can compose your class as needed. You can create a class that requires a type safe ByteDataWriter
. Then the compiler has to make sure that it can only match with the correct class. No class needed. The downside is that you cannot reconfigure dependencies using a config file. But this is usually not necessary because the supported options are well known at compile time.
Conclusion: try to reformulate when possible
If you have this option, consider redesigning your code using one of the methods above to get rid of the class. It is very likely that you will have the same problem in many other places in your code.
source to share