Reputation: 7327
Simple question about reflection in Scala :
fields
that returns all the fields of a certain type, even in subclasses?Example :
class Top { def fields = ... }
class A extends Top {
val f1 = Field(...)
val f2 = Field(...)
}
(new A).fields // List(f1, f2)
Upvotes: 2
Views: 590
Reputation: 14083
So, in my trials and errors, I've found genuine run-time type reflection to be difficult, because of Scala's trick of embedding type information at compile time when you ask for an implicit TypeTag. What I've found is that, if you want to reflect on the Type of an object, that object's type must have been available at compile time. (That may reflect a limitation of my knowledge rather than a limitation of Scala reflection, but I have tried and so far failed to reflect on runtime types that cannot be captured at compile time.)
So, here is closest to what you want that I know how to do:
scala> import scala.reflect.runtime.universe._;
import scala.reflect.runtime.universe._
scala> class Base[T <: Base[T] : TypeTag] {
| def stringVals = typeOf[T].members.filter( _.isTerm ).map( _.asTerm).filter( _.isVal ).filter( _.typeSignature <:< typeOf[String] )
| }
defined class Base
scala> class Derived extends Base[Derived] {
| val f1 = "Bye";
| val f2 = 27;
| val f3 = "Sad.";
| }
defined class Derived
scala> (new Derived).stringVals
res0: Iterable[reflect.runtime.universe.TermSymbol] = List(value f3, value f1)
Note that I had to explicitly name my own type when I extended Base, so that at compile time, the appropriate TypeTag could be embedded (as an implicit into my constructor). I just don't know a way around that.
The vals are returned here in the form of a List of TermSymbols. I'm not sure what you wanted; if you just wanted String val names, add ".map( _.name.toString.trim )" to the end of the stringVals function. (I've found the call to trim to be important in practice, but I bet as the reflection library finalizes and evolves it will become superfluous.)
Good luck!
Upvotes: 4