Reputation: 4481
My question is how to iterate inner objects in a defined object in Scala using Scala reflection package
?
object Units {
val values = CITIZEN :: WORKER :: Nil // I need something reflectional to list all of the case objects
case object CITIZEN extends Population
case object WORKER extends Population
}
Upvotes: 2
Views: 328
Reputation: 139038
There are lots of ways to do this, but I'd suggest using macros (compile-time reflection) over runtime reflection, for the sake of both performance and (more importantly) type safety.
Here's a quick implementation with macros:
import scala.language.experimental.macros
object MacroUtils {
import scala.reflect.macros.Context
def values = macro MacroUtils.values_impl
def values_impl(c: Context) = {
import c.universe._
val objs = c.enclosingClass.collect {
case ModuleDef(mods, name, _) if mods hasFlag Flag.CASE => Ident(name)
}
c.Expr[List[Any]](
Apply(Select(reify(List).tree, newTermName("apply")), objs.toList)
)
}
}
trait Population
object Units {
val values = MacroUtils.values
case object CITIZEN extends Population
case object WORKER extends Population
}
And then, for example:
scala> val populations: List[Population] = Units.values
populations: List[Population] = List(CITIZEN, WORKER)
Note that the compiler knows that the list of case objects can be statically typed as a list of populations.
Upvotes: 5
Reputation: 6930
I'm not sure if this is the best way to do it, but here it is:
object Units {
val values = CITIZEN :: WORKER :: Nil
trait Population
case object CITIZEN extends Population
case object WORKER extends Population
val reflectionValues = {
import scala.reflect.runtime.{universe => ru}
val mirror = ru.runtimeMirror(getClass.getClassLoader)
val objects = ru.typeOf[Units.type].declarations.filter(_.isModule)
objects.map(o => mirror.reflectModule(o.asModule).instance.asInstanceOf[Population]).toList
}
def main(args: Array[String]) {
assert(values == reflectionValues)
}
}
Upvotes: 1