I'd like to build a wrapper for isInstanceOf[T]
and asInstanceOf[T]
pair that would output Option[T]
with convenient map
and getOrElse
methods.
So I give a try, but the result has disappointed me.
import scala.reflect.runtime.universe.{TypeTag, typeOf}
class Base()
class Deep() extends Base
class Deeper() extends Deep()
final case class WrapSimple[T](source : T) {
def cast[U] : Option[U] =
if (source.isInstanceOf[U]) Some(source.asInstanceOf[U]) else None
}
final case class WrapFullTagged[T: TypeTag](source : T) {
def cast[U : TypeTag] : Option[U] =
if (typeOf[T] <:< typeOf[U]) Some(source.asInstanceOf[U]) else None
}
final case class WrapHalfTagged[T](source : T) {
val stpe = {
val clazz = source.getClass
val mirror = scala.reflect.runtime.universe.runtimeMirror(clazz.getClassLoader)
mirror.classSymbol(clazz).toType
}
def cast[U : TypeTag] : Option[U] =
if (stpe <:< typeOf[U]) Some(source.asInstanceOf[U]) else None
}
object Test {
val base = new Base
val deep = new Deep
val deeper = new Deeper
val wile : Deep = new Deeper
def testSimple() : Unit = {
println(WrapSimple(deep).cast[Base].isDefined) // should be true
println(WrapSimple(deep).cast[Deeper].isDefined) // should be false
println(WrapSimple(wile).cast[Deeper].isDefined) // should be true
}
def testFullTagged() : Unit = {
println(WrapFullTagged(deep).cast[Base].isDefined) // should be true
println(WrapFullTagged(deep).cast[Deeper].isDefined) // should be false
println(WrapFullTagged(wile).cast[Deeper].isDefined) // should be true
}
def testHalfTagged() : Unit = {
println(WrapHalfTagged(deep).cast[Base].isDefined) // should be true
println(WrapHalfTagged(deep).cast[Deeper].isDefined) // should be false
println(WrapHalfTagged(wile).cast[Deeper].isDefined) // should be true
}
def testAll() : Unit = {
testSimple()
testFullTagged()
testHalfTagged()
}
}
WrapSimple
looks good, but just does not work, it erases the U
type in the isInstanceOf[U]
method application, so it is always responds with true
. The funny thing is that asInstanceOf[U]
keeps the U
type normally, so it just produces runtime exceptions.
The second approach I had tried is WrapFullTagged
that employs type tags. It seems clear enough, but again plainly breaks the contract. It could only check static types at compile time and has zero insight about actual types in runtime.
So, I breed both approaches and gave birth to the third, that at least produces correct output. But it looks awful and invokes power of reflection that comes with a great cost.
Is it possible to solve the issue with greater elegance?
Aucun commentaire:
Enregistrer un commentaire