I have an abstract path-dependent type that I need to ClassTag of. Is there a better way than manually pulling the implicit for each concrete derived class?
trait Foo {
type A // : ClassTag // Need the ClassTag of A later
val ctA: ClassTag[A] // But can't put a context-bound on the type
}
class IntFoo extends Foo {
type A = Int
val ctA = implicitly[ClassTag[Int]]
}
class StringFoo extends Foo {
type A = String
val ctA = implicitly[ClassTag[String]]
}
You have to conjure a class tag where you know the type.
scala> :pa
// Entering paste mode (ctrl-D to finish)
trait Foo {
type A
def ct[B: ClassTag] = implicitly[ClassTag[B]]
}
// Exiting paste mode, now interpreting.
defined trait Foo
scala> :pa
// Entering paste mode (ctrl-D to finish)
class IntFoo extends Foo {
type A = Int
def myct = ct[A]
}
// Exiting paste mode, now interpreting.
defined class IntFoo
scala> new IntFoo().myct
res2: scala.reflect.ClassTag[Int] = Int
But macros are pretty easy to write these days.
scala> :pa
// Entering paste mode (ctrl-D to finish)
object M {
def ct[A: c.WeakTypeTag](c: Context): c.Expr[ClassTag[A]] = {
import c.universe._
val a = c.prefix.tree.tpe.member(TypeName("A")).typeSignature
c.Expr(q"implicitly[ClassTag[$a]]").asInstanceOf[c.Expr[ClassTag[A]]]
}}
// Exiting paste mode, now interpreting.
scala> class Foo { type A = Int ; def f: ClassTag[A] = macro M.ct[A] }
defined class Foo
scala> new Foo().f
res15: scala.reflect.ClassTag[Int] = Int
scala> class Bar { type A = Char ; def f: ClassTag[A] = macro M.ct[A] }
defined class Bar
scala> new Bar().f
res16: scala.reflect.ClassTag[Char] = Char
so
scala> trait Foo { type A ; def ct = macro M.ct[A] }
defined trait Foo
scala> class Bar extends Foo { type A = Int ; def p = println(ct) }
defined class Bar
scala> new Bar().p
Int
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With