Home > Software design >  Return singleton/object from method
Return singleton/object from method

Time:01-30

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

Get instance of singleton type in scala

Scala object import in runtime

  • Related