0

I have a trait that's implemented by a large number of classes, and I'd like to use the names of the classes that implement this trait at runtime, but with as much code centralized as possible.

Specifically, in my code, I'm using tokens to represent classes to be initialized at runtime. The tokens carry configuration, and the actual class is instantiated as needed via the token, combined with run-time information. For linking with resources outside of my app, I want to be able to access the name of the class for which a token is defined. See the example:

trait Token[Cls] {
  val className = ???

  // Example generic method depending on final class name
  def printClassName = println(className)
}

case class ClassA(t: ClassAToken, runtimeContext: String) {
  // a bunch of other code
}

object ClassA {
  case class ClassAToken(configParam: String) extends Token[ClassA]
}

So, I'm trying to implement className. Ideally, I can pull this information once at compile time. How can I do this, while keeping boilerplate code out of ClassA? Although, if I can drop the type parameter and get the name of the class implementing the Token trait at runtime, that's great too.

acjay
  • 34,571
  • 6
  • 57
  • 100

1 Answers1

1

Due to Type Erasure Cls is not available on runtime anymore. To get the informations at runtime, you need to use a TypeTag (in your case a ClassTag).

Your code could look like this:

import scala.reflect._

trait Token[Cls] {
  def className(implicit ct: ClassTag[Cls]) = ct.runtimeClass.getName

  // Example generic method depending on final class name
  def printClassName(implicit ct: ClassTag[Cls]) = println(className)
}

case class ClassA(t: ClassAToken, runtimeContext: String) {
  // a bunch of other code
}

object ClassA {
  case class ClassAToken(configParam: String) extends Token[ClassA]
}

or if it is possible for you to let Token be an class, you could use the ClassTag context bounds:

import scala.reflect._

class Token[Cls: ClassTag] {
  def className = classTag[Cls].runtimeClass.getName

  // Example generic method depending on final class name
  def printClassName = println(className)
}

case class ClassA(t: ClassAToken, runtimeContext: String) {
  // a bunch of other code
}

object ClassA {
  case class ClassAToken(configParam: String) extends Token[ClassA]
}

For more informations on TypeTags/ClassTags see Scala: What is a TypeTag and how do I use it?

Community
  • 1
  • 1
regexp
  • 766
  • 4
  • 14
  • I could only get this to finally work when converting `Token` to a class, as in your second example. I had read about TypeTags and ClassTags, but I think what really tripped me up was that in the exact way I'm using this in my code, it just doesn't work with `trait`. Fortunately, it's no problem here to use a `class` instead. Thanks – acjay Jul 19 '14 at 13:53