2

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
}

2 Answers 2

5

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.

Sign up to request clarification or add additional context in comments.

4 Comments

There is a problem, macro implementation must be in statically accessible object in def values = macro MacroUtils.values_impl
Did you move the definition of the values method? It works for me exactly as pasted above.
Yes, I had a mistake in the Units object
The process takes only one millisecond
1

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)
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.