How can I get the actual object referred to by Scala 2.10 reflection?

reflection, scala, scala-2.10

Solution

scala> val moduleClass = typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre.typeSymbol
moduleClass: reflect.runtime.universe.Symbol = object ResponseType

scala> val module = moduleClass.owner.typeSignature.member(moduleClass.name.toTermName)
module: reflect.runtime.universe.Symbol = object ResponseType

scala> reflect.runtime.currentMirror.reflectModule(module.asModule).instance
res9: Any = ResponseType

Now, some explanation is in order, since this is quite an obscure implementation detail we've (yet!) been unable to abstract over in the public API.

For every `object` Scala creates an underlying class that represents its signature, internally called module class. For example, if you compile `object C` the compiler will generate `C$.class`. That's exactly the module class.

Note that module classes are different from companion classes. Say, for `case class C`, the compiler will generate three symbols: `type C`, `term C` and (another one) `type C`, where the first `type C` represents the class C (which contains auto-generated copy, productPrefix, productArity etc) and the second `type C` represents a signature of object C (which contains auto-generated factory, extractor etc). There won't be any name clashes, because the module class isn't added to the symbol table directly and is only available through `<module>.moduleClass`.

So what you actually get from your `typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre.typeSymbol` incantation is a symbol that stands for a module class. There's no function in the API that would get you to a module symbol from a module class. Internally in the compiler there surely is one, but we decided not to expose this implementation detail, because it might very well change soon.

To get to a source module you need to go to `owner`, peek into the list of its members and look up an object there having the same name as the module class has. That's exactly what `moduleClass.owner.typeSignature.member(moduleClass.name.toTermName)` does. One minor caveat is that if in the same scope you have a method with the same name, then `member` will return an overloaded symbol, and you'll need to do something like `.member(...).suchThat(_.isModule)`.

After that it's a piece of cake.

Edit. Actually we're thinking of introducing `ClassSymbol.module` that would return source module symbol for a module class and NoSymbol otherwise. Quite probably this will end up in RC1. Follow the release notes.

Problem

Please consider this code: ``` object ResponseType extends Enumeration { val Listing, Album = Value } ``` I can get the `Symbol` referring to this object like so: ``` import reflect.runtime.universe._ val s = typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre.typeSymbol ``` Now, having this symbol, how can I get the actual `ResponseType` object?

Original source