Search code examples
scalatraitstype-systems

Get name of abstract type


I'm trying to create a trait that would provide the name of the abstract type that is added in the sub-class:

trait T {
  type T
  def myClassOf[T:ClassTag] = implicitly[ClassTag[T]].runtimeClass
  def getType = {
    myClassOf[T].getSimpleName
  }
}

class TT extends T {
  type T = String
}

However, this fails to compile:

Error:(7, 15) not enough arguments for method myClassOf: (implicit evidence$1: scala.reflect.ClassTag[T.this.T])Class[_].
Unspecified value parameter evidence$1.
    myClassOf[T].getSimpleName
             ^

But it works fine if I move the getType method to the sub-class. Can someone explain why and whether there is a way to do this call from the sub-class?


Solution

  • At the point where you call myClassOf[T] T is still abstract, so the compiler can not generate a ClassTag for it. You can fix it by delaying the generation of the ClassTag[T] until T is known.

    trait Trait {
      type T
      def myClassOf[A:ClassTag] = implicitly[ClassTag[A]].runtimeClass
      def getType(implicit tag: ClassTag[T]) = {
        myClassOf[T].getSimpleName
      }
    }
    
    class Sub extends Trait {
      type T = String
    }
    

    If adding an implicit parameter is impossible for some reason I think the best way is probably requiring some method getClassT to be implemented in subclasses. Since its return type is Class[T] it's difficult to provide a wrong implementation in a subclass.

    trait Trait {
      type T
      def getType = {
        getClassT.getSimpleName
      }
      def getClassT: Class[T]
    }
    
    class Sub extends Trait {
      type T = String
      def getClassT = classOf[T]
    }