I have a method in Scala 2 that uses reflection. It doesn't work in Scala 3, and I would like to reimplement it so it works for Scala 3. (I will no longer need it for Scala 2 anymore, so it need not work for both).
The purpose of the method is to examine an object and collect any instances of singleton objects it has as members, in order of declaration. (It is known by the programmer ahead of time that all such singleton objects extend A
).
It is working correctly.
def allSingletonObjects[A](host: Any): Vector[A] = {
import scala.reflect.runtime.universe.runtimeMirror
val mirror = runtimeMirror(host.getClass.getClassLoader)
mirror
.classSymbol(host.getClass)
.info
.members
.filter(_.isModule)
.map(sym => mirror.reflectModule(sym.asModule).instance.asInstanceOf[A])
.toVector
.reverse
}
Here's an an example of how it is used.
sealed trait Color
object Color {
case object Red extends Color
case object Green extends Color
case object Blue extends Color
}
In this example, allSingletonObjects[Color](Color)
would return Vector(Color.Red, Color.Green, Color.Blue)
.
How would I implement allSingletonObjects
in Scala 3?
Note: I am not able to change the way I am modeling the types (e.g. using enums). I would ideally just like allSingletonObjects
to work as it did in Scala 2.
I agree with the comments, you should probably find a better way to do this, but here is a working version:
import scala.quoted.*
inline def allSingletonObjects[A](host: Any) = allSingletonObjectsSeq[A](host).toVector
inline def allSingletonObjectsSeq[A](host: Any) = ${allSingletonObjectsSeqImpl[A]('host)}
def allSingletonObjectsSeqImpl[A: Type](host: Expr[Any])(using quotes: Quotes): Expr[Seq[A]] =
import quotes.reflect.*
Expr.ofSeq:
host
.asTerm
.tpe
.classSymbol
.get
.declarations
.filter(sym => sym.flags.is(Flags.Case | Flags.Final | Flags.Lazy | Flags.Module | Flags.StableRealizable))
.map(sym => Ref(sym).asExprOf[A])