scalasingleton-typescala-2.12

Return singleton/object from method


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.


Solution

  • 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

    Get instance of singleton type in scala

    Scala object import in runtime