How can I make this work?
def getSingleton[T <: scala.Singleton]: T = {
???
}
object X
val x = getSingleton[X.type]
Or similar, appreciate the signature may need to change slightly.
CodePudding user response:
In Scala 2.13 there is built-in type class ValueOf
1 2 3
def getSingleton[T <: Singleton](implicit valueOf: ValueOf[T]): T = valueOf.value
In Scala 2.12 you can use type class Witness
from Shapeless 1 2
// libraryDependencies = "com.chuusai" %% "shapeless" % "2.3.10"
import shapeless.Witness
def getSingleton[T <: Singleton](implicit witness: Witness.Aux[T]): T = witness.value
Or if you prefer not to depend on Shapeless you can write a macro
// libraryDependencies = scalaOrganization.value % "scala-reflect" % scalaVersion.value
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def getSingleton[T <: Singleton]: T = macro getSingletonImpl[T]
def getSingletonImpl[T <: Singleton : c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
// q"${weakTypeOf[T].typeSymbol.name.toTermName}"
// q"${weakTypeOf[T].dealias.typeSymbol.asClass.module}" // dealiased version
q"${symbolOf[T].asClass.module}" // not dealiased version
}
All the above works at compile time. If it's enough to get the value at runtime you can use Scala runtime reflection with TypeTag
import scala.reflect.runtime.{currentMirror => rm}
import scala.reflect.runtime.universe._
def getSingleton[T: TypeTag]: T =
rm.reflectModule(symbolOf[T].asClass.module.asModule).instance.asInstanceOf[T]
or with ClassTag
import scala.reflect.{ClassTag, classTag}
def getSingleton[T: ClassTag]: T =
rm.reflectModule(rm.moduleSymbol(classTag[T].runtimeClass)).instance.asInstanceOf[T]
or if you prefer not to depend on scala-reflect
you can use Java reflection
def getSingleton[T: ClassTag]: T =
classTag[T].runtimeClass.getField("MODULE$").get(null).asInstanceOf[T]
In scala, is it possible to initialise a singleton object from a TypeTag?
Get the module symbol, given I have the module class, scala macro