Reputation: 5642
In Scala, how can we determine if a class is a subclass of a parent class or a trait? For example:
trait MyTrait
class MyParentClass()
class MyOtherParentClass()
case class MySubClass() extends MyParentClass with MyTrait
case class MyOtherSubClass() extends MyOtherParentClass
Is it possible to identify if class such as MySubClass
extends from MyParentClass
or MyTrait
without instantiating an object and through reflection APIs? Given an unknown generic type T
, I am interested in having it match a case if T
extends a particular parent class or a trait:
def example[T](): Unit = {
T match {
case if T extends MyParentClass => ...
case if T extends MyOtherParentClass => ...
case if T extends MyOtherTrait => ...
case _ => default case ...
}
Upvotes: 0
Views: 1286
Reputation: 51658
If you write
case class MySubClass() extends MyParentClass with MyTrait
then obviously MySubClass
extends MyParentClass
and MyTrait
so you can check that for a generic type T
with
def test[T](implicit ev: T <:< MyParentClass, ev1: T <:< MyTrait) = ???
test[MySubClass] // compiles
at compile time.
If the thing is you want to check that with OR instead of AND, then you can use shapeless.OrElse
or implicitbox.Priority
Scala method that needs either one of two implicit parameters
I updated the question with an example of the desired usage
It seems you want a type class
trait Example[T] {
def example(): Unit
}
object Example {
implicit def subtypeOfMyParentClass[T <: MyParentClass] = new Example[T] {
override def example(): Unit = ???
}
implicit def subtypeOfMyOtherParentClass[T <: MyOtherParentClass] = new Example[T] {
override def example(): Unit = ???
}
implicit def subtypeOfMyOtherTrait[T <: MyOtherTrait] = new Example[T] {
override def example(): Unit = ???
}
implicit def default[T] = new Example[T] {
override def example(): Unit = ???
}
}
def example[T]()(implicit e: Example[T]): Unit = e.example()
A type class is a compile-time (i.e. type-level) replacement for pattern matching.
If there is ambiguity among implicits you can prioritize them.
Just curious, do you know if there is a way to do this in a simple one line conditional such as
if (T extends from MyParentClass) then ...
through reflection APIs (is it possible throughclassOf[]
ortypeOf[]
?)
You can do that at runtime
import scala.reflect.runtime.universe._
def example[T: TypeTag](): Unit =
if (typeOf[T] <:< typeOf[MyParentClass]) ???
else if (typeOf[T] <:< typeOf[MyOtherParentClass]) ???
else if (typeOf[T] <:< typeOf[MyOtherTrait]) ???
else ???
or
import scala.reflect.ClassTag
def example[T: ClassTag](): Unit =
if (classOf[MyParentClass] isAssignableFrom classOf[T]) ???
else if (classOf[MyOtherParentClass] isAssignableFrom classOf[T]) ???
else if (classOf[MyOtherTrait] isAssignableFrom classOf[T]) ???
else ???
or at compile time
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def example[T](): Unit = macro exampleImpl[T]
def exampleImpl[T: c.WeakTypeTag](c: blackbox.Context)(): c.Tree = {
import c.universe._
if (weakTypeOf[T] <:< typeOf[MyParentClass]) ???
else if (weakTypeOf[T] <:< typeOf[MyOtherParentClass]) ???
else if (weakTypeOf[T] <:< typeOf[MyOtherTrait]) ???
else ???
}
But implicits and types is a preferable way rather than (compile-time or especially runtime) reflection. It's not clear why you need reflection at all.
https://users.scala-lang.org/t/how-to-access-the-method/6281
Upvotes: 5