My code:
import scala.reflect.runtime
import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
object Stuff {
val rm: universe.Mirror = runtime.currentMirror
val tb: ToolBox[universe.type] = rm.mkToolBox()
val Example1 = tq"namespace.to.Example1"
val Example2 = tq"namespace.to.Example2"
val classDef = tb
.define(
q"""
case class MyClass extends $Example1 { //
def doWork(): $Example2 = {
Example2("hello") // <-- I believe this is the offending line
}
}
""".asInstanceOf[ClassDef]
).asClass
}
where Example2:
case class Example2(member: String)
I run into this error:
Cause: scala.tools.reflect.ToolBoxError: reflective compilation has failed:
not found: value Example2
I've tried this too:
def doWork(): $Example2 = {
$Example2("hello")
}
but that runs into:
class namespace.to.Example2 is not a value
Using $Example2 as the type of the method works, but how do I make the reflection understand creating an instance of Example2?
EDIT:
How would I also reference Example2 if it were another class that I had to compile at runtime? If I want this at runtime without having a namespace.to.Example2 (class doesn't exist)
case class Example2(member: String) {
def aMe: Example2 = {
// do any work
}
}
object Stuff {
val rm: universe.Mirror = runtime.currentMirror
val tb: ToolBox[universe.type] = rm.mkToolBox()
val classDef = tb
.define(
q"""
case class MyClass {
def doWork(): $Example2 = {
val ex = new $Example2("hello") // <-- this would not work?
ex.aMethod()
}
}
}
Because there is no val Example2 = tq"namespace.to.Example2", the new Example2("hello") probably doesn't work.
Use splicing (
${...}) and either the constructor of case classor
applymethod of companion objectThe string interpolator
tq"..."creates a type tree,q"..."creates a term treehttps://docs.scala-lang.org/overviews/quasiquotes/intro.html
If
Example1andExample2are ordinary classes (not runtime-generated) you can use them staticallyNormally you can use imports inside quasiquotes with
tb.eval,tb.compile,tb.typecheckbut not with
tb.definebecause it acceptsClassDef/ModuleDef(<: ImplDef <: Tree) rather than arbitraryTreeand adding imports makes a tree aBlock(<: Tree).Make use of the class symbol returned by
tb.defineon the previous step (you can splice trees, symbols, types into trees)Or if this is enough, just