scala get generic type by class - scala

Is it possible pass generic parameter using class:
def m(clazz: Class[_]): Unit = {
m2[] //here I want to exact type (that I should have because I have Class)
}
def m2[C: ClassTag]() : List[C] = {
println("hi")
List.empty
}
Any Ideas?

IIUC you want to call a method that requires a ClassTag while all you have is a Class. You can create a ClassTag from a Class like this:
def m(clazz: Class[_]): Unit = {
m2()(ClassTag(clazz))
}

ClassTags (as well as TypeTags and WeakTypeTags) are for persisting some compile-time information till runtime. You want to do something in reverse direction. You want, having runtime information (clazz: Class[_]), to do something at compile time (specify type parameter C of m2). So ClassTags are irrelevant.
You can call compiler at runtime
import scala.tools.reflect.ToolBox
import scala.reflect.runtime.currentMirror
object App {
val tb = currentMirror.mkToolBox()
def m(clazz: Class[_]): Unit = {
tb.eval(tb.parse(s"import App._; m2[${clazz.getName}]"))
}
def m2[C]() : List[C] = {
println("hi")
List.empty
}
def main(args: Array[String]): Unit = {
m(classOf[String]) //hi
}
}
libraryDependencies ++= Seq(
scalaOrganization.value % "scala-reflect" % scalaVersion.value,
scalaOrganization.value % "scala-compiler" % scalaVersion.value,
)

Related

Invoke constructor based on passed parameter

Constructing an object based on passed parameter. But the parameter is not String.
I found the solution how to do it with String
Scala instantiate objects from String classname
but I believe that it can be done nicer.
Let's say the following classes:
sealed trait Figure
object Figure {
final case class Circle(radius: Double) extends Figure
final case class Square(a: Double) extends Figure
}
And let's define a function (which doesn't make sense) which take a parameter based on I can invoke the proper constructor:
val construct123: Figure => Either[String, Figure] = (figure: Figure) => Right(figure.apply(1.23))
I want to invoke
construct123(Circle)
//or
construct123(Square)
Is it even possible?
The easiest would be to modify the signature of construct123 slightly
def construct123(figure: Double => Figure): Either[String, Figure] =
Right(figure(1.23))
construct123(Circle.apply) // Right(Circle(1.23))
construct123(Square.apply) // Right(Square(1.23))
construct123(Circle(_)) // Right(Circle(1.23))
construct123(Square(_)) // Right(Square(1.23))
construct123(Circle) // Right(Circle(1.23))
construct123(Square) // Right(Square(1.23))
Or construct123 can be written as a higher-order function
val construct123: (Double => Figure) => Either[String, Figure] =
figure => Right(figure(1.23))
Difference between method and function in Scala
Circle and Square in construct123(Circle) and construct123(Square) are not the case classes Circle and Square but their companion objects
Class companion object vs. case class itself
So actually you want to transform an object into an instance of its companion class. You can do this for example with a macro
// libraryDependencies += scalaOrganization.value % "scala-reflect" % scalaVersion.value
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def construct123[A](figure: A): Either[String, Figure] = macro construct123Impl[A]
def construct123Impl[A: c.WeakTypeTag](c: blackbox.Context)(figure: c.Tree): c.Tree = {
import c.universe._
val companionClass = weakTypeOf[A].companion
q"_root_.scala.Right.apply(new $companionClass(1.23))" // using constructor of the case class
}
or
def construct123Impl[A: c.WeakTypeTag](c: blackbox.Context)(figure: c.Tree): c.Tree = {
import c.universe._
val A = symbolOf[A].asClass.module
q"_root_.scala.Right.apply($A.apply(1.23))" // using apply method of the companion object
}
Testing (in a different subproject):
construct123(Circle) // Right(Circle(1.23))
construct123(Square) // Right(Square(1.23))
// scalacOptions += "-Ymacro-debug-lite"
//scalac: scala.Right.apply(new Macros.Figure.Circle(1.23))
//scalac: scala.Right.apply(new Macros.Figure.Square(1.23))
//scalac: scala.Right.apply(Circle.apply(1.23))
//scalac: scala.Right.apply(Square.apply(1.23))
You can hide the work with macros in type classes (defined with whitebox implicit macros). The type class ToCompanion below is similar to HasCompanion in Get companion object of class by given generic type Scala (answer). The type class Generic from Shapeless (used below to define construct123) is also macro-generated. Some intros to type classes (ordinary, not macro-generated): 1 2 3 4 5 6 7 8 9
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
// type class
trait ToCompanion[A] {
type Out
}
object ToCompanion {
type Aux[A, Out0] = ToCompanion[A] {type Out = Out0}
// materializer
def apply[A](implicit tcc: ToCompanion[A]): ToCompanion.Aux[A, tcc.Out] = tcc
// def apply[A](implicit tcc: ToCompanion[A]): tcc.type = tcc
// instance of the type class
implicit def mkToCompanion[A, B]: ToCompanion.Aux[A, B] = macro mkToCompanionImpl[A]
// implicit def mkToCompanion[A]: ToCompanion[A] = macro mkToCompanionImpl[A] // then implicitly[ToCompanion.Aux[Circle, Circle.type]] doesn't compile in spite of white-boxity
def mkToCompanionImpl[A: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val A = weakTypeOf[A]
val companion = A.companion
val ToCompanion = weakTypeOf[ToCompanion[A]]
q"new $ToCompanion { type Out = $companion }"
}
}
implicitly[ToCompanion.Aux[Circle, Circle.type]] // compiles
implicitly[ToCompanion.Aux[Circle.type, Circle]] // compiles
val tc = ToCompanion[Circle.type]
implicitly[tc.Out =:= Circle] // compiles
val tc1 = ToCompanion[Circle]
implicitly[tc1.Out =:= Circle.type] // compiles
// libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.10"
import shapeless.{::, Generic, HNil}
def construct123[A, B <: Figure](figure: A)(implicit
toCompanion: ToCompanion.Aux[A, B],
generic: Generic.Aux[B, Double :: HNil]
): Either[String, Figure] = Right(generic.from(1.23 :: HNil))
construct123(Circle) // Right(Circle(1.23))
construct123(Square) // Right(Square(1.23))
Since all the classes are now known at compile time it's better to use compile-time reflection (the above macros). But in principle runtime reflection can be used too
import scala.reflect.runtime.{currentMirror => rm}
import scala.reflect.runtime.universe._
def construct123[A: TypeTag](figure: A): Either[String, Figure] = {
val classSymbol = symbolOf[A].companion.asClass
//val classSymbol = typeOf[A].companion.typeSymbol.asClass
val constructorSymbol = typeOf[A].companion.decl(termNames.CONSTRUCTOR).asMethod
val res = rm.reflectClass(classSymbol).reflectConstructor(constructorSymbol)(1.23).asInstanceOf[Figure]
Right(res)
}
or
import scala.reflect.ClassTag
import scala.reflect.runtime.{currentMirror => rm}
import scala.reflect.runtime.universe._
def construct123[A: TypeTag : ClassTag](figure: A): Either[String, Figure] = {
val methodSymbol = typeOf[A].decl(TermName("apply")).asMethod
val res = rm.reflect(figure).reflectMethod(methodSymbol).apply(1.23).asInstanceOf[Figure]
Right(res)
}
Or you can use structural types aka duck typing (i.e. also runtime reflection under the hood)
import scala.language.reflectiveCalls
def construct123(figure: { def apply(x: Double): Figure }): Either[String, Figure] =
Right(figure(1.23))

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.
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

How do I properly create a unit test for a class method while stubbing other methods in Scala?

I have a class and a method I am testing (SUTClass.a() in the example solution below). I want to create a test case that:
runs the body of a() while subordinated methods are stubbed (b(), c())
verify that b() and c() have been called exactly one time
The reason to stub methods that are not under test is that they could do some expensive disk/network operation. Also, in unit testing, you are supposed to isolate the code under test as much as possible.
In a solution I came up with I inject stubbed b() and c() as parameters to a(). However, if there are more methods to stub (think of d(), e() etc) the solution becomes a mess. Is there a better way?
As an alternative solution (when class under test is a Scala object) it is advised to create file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker. However I consider it a poor approach.
Related posts:
https://github.com/mockito/mockito-scala#mocking-scala-object
Solution:
import org.mockito.MockitoSugar.{doNothing, mock, times, verify}
import org.scalatest.FlatSpec
trait SUTClassMethods {
def a( b: ()=>Unit, c: ()=>Unit )
def b()
def c()
}
class SUTClass extends SUTClassMethods {
def a( b: () => Unit = b, c: () => Unit = c ): Unit = {
println("Hello from a()")
b()
c()
}
def b(): Unit = println("Actual implementation of b()")
def c(): Unit = println("Actual implementation of c()")
}
class DependencyInjectionTest extends FlatSpec {
behavior of "a()"
it should "make call to b() and c() but actual implementations must not be executed" in {
val mockSUTClass = mock[SUTClassMethods]
doNothing.when(mockSUTClass).b()
doNothing.when(mockSUTClass).c()
(new SUTClass).a(mockSUTClass.b, mockSUTClass.c)
verify(mockSUTClass, times(1)).b()
verify(mockSUTClass, times(1)).c()
}
}
I am using Scala 2.11 and here is excerpt from my build.sbt:
scalaVersion := "2.11.12"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.8" % Test
libraryDependencies += "org.mockito" %% "mockito-scala" % "1.16.32" % Test

Printing MirroredElemTypes in Scala 3

I am trying to modify this standard example to print values with the types.
And I am stuck with p.MirroredElemTypes. I haven't found any API to traverse and stringify types.
To check MirroredElemTypes you can just summon
import scala.deriving.Mirror
case class A(i: Int, s: String, b: Boolean)
val m = summon[Mirror.Of[A]]
summon[m.MirroredElemTypes =:= (Int, String, Boolean)] // compiles
But if you want to print MirroredElemTypes you can do the following.
For some reason Typeable doesn't work now but in its error message it prints the type
// scalaVersion := "3.0.2"
// libraryDependencies += "org.typelevel" %% "shapeless3-typeable" % "3.0.3"
import shapeless3.typeable.Typeable
summon[Typeable[m.MirroredElemTypes]].describe
// Typeable for sum type scala.*:[scala.Int, scala.*:[scala.Predef.String, scala.*:[scala.Boolean, scala.Tuple$package.EmptyTuple]]] with no Mirror
Alternatively you can write a simple macro
import scala.quoted.*
inline def describe[A]: String = ${describeImpl[A]}
def describeImpl[T: Type](using Quotes): Expr[String] = {
import quotes.reflect.*
Literal(StringConstant(TypeRepr.of[T].dealias.show)).asExprOf[String]
}
// in a different file
describe[m.MirroredElemTypes]
// scala.*:[scala.Int, scala.*:[scala.Predef.String, scala.*:[scala.Boolean, scala.Tuple$package.EmptyTuple]]]
In Scala 3.2.0 + Shapeless 3.2.0 Typeable works properly
https://scastie.scala-lang.org/DmytroMitin/1R6N3ZOJS46DJJqtQDU0lw

Using Scala Macro Annotation in Intellij

I am trying to use scala macro annotation to simply print return value from a method. I am using Intellij 2017. Here is the code:
class PrintResult extends StaticAnnotation {
def macroTransform(annottees: Any*) = macro PrintResult.impl
}
object PrintResult {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
val result = {
annottees.map(_.tree).toList match {
case q"$mods def $methodName(...$args): $returnType = { ..$body }" :: Nil => {
q"""$mods def $methodName(...$args): $returnType = {
val res = {..$body}
println($res)
res
}"""
}
case _ => c.abort(c.enclosingPosition, "Annotation #PrintResult can be used only with methods")
}
}
c.Expr[Any](result)
}
}
#PrintResult
object Test extends App {
def add(a: Int, b: Int): Int = {
a+b
}
}
I added this config to sbt:
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
I also added SBT Compile to Intellij Run Configuration.
I am getting this error:
macro annotation could not be expanded (the most common reason for that is that you need to enable the macro paradise plugin; another possibility is that you try to use macro annotation in the same compilation run that defines it)
To quote the error message:
another possibility is that you try to use macro annotation in the same compilation run that defines it
object Test must be in a different subproject or in src/test/scala (when PrintResult is in src/main/scala).