views:

214

answers:

3

I need the object (or "singleton object" or "companion object"... anything but the class) defined by a string name. In other words, if I have:

package myPackage object myObject

...then is there anything like this:

GetSingletonObjectByName("myPackage.myObject") match { case instance: myPackage.myObject => "instance is what I wanted" }

+2  A: 

Scala is still missing a reflection API. You can get the an instance of the companion object by loading the companion object class:

import scala.reflect._
def companion[T](implicit man: Manifest[T]) : T = 
  man.erasure.getField("MODULE$").get(man.erasure).asInstanceOf[T]


scala> companion[List$].make(3, "s")
res0: List[Any] = List(s, s, s)

To get the untyped companion object you can use the class directly:

import scala.reflect.Manifest
def companionObj[T](implicit man: Manifest[T]) = { 
  val c = Class.forName(man.erasure.getName + "$")
  c.getField("MODULE$").get(c)
}


scala> companionObj[List[Int]].asInstanceOf[List$].make(3, "s")
res0: List[Any] = List(s, s, s)

This depends on the way scala is mapped to java classes.

Thomas Jung
Holy cow. Do you know if this syntax is a fixed part of the Scala spec (as fixed as anything else in the language, anyway)? It seems like a bad idea to rely on this. And since my goal was to make the code *clearer*... Thank you!
Dave
+1  A: 

Barring reflection tricks, you can't. Note, for instance, how the method companion is defined on Scala 2.8 collections -- it is there so an instance of a class can get the companion object, which is otherwise not possible.

Daniel
Could you add a link to the source, please?
Thomas Jung
http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/scala, though, hopefully, 2.8's Scaladoc 2 will soon contain links to the source, as already happens with 2.7.
Daniel
+1  A: 

Adjustment to Thomas Jung's answer above: you would do better to say companion[List.type] because a) this should be a stable way to refer to it, not dependant on the name mangling scheme and b) you get the unerased types.

def singleton[T](implicit man: reflect.Manifest[T]) = {
  val name = man.erasure.getName()
  assert(name endsWith "$", "Not an object: " + name)
  val clazz = java.lang.Class.forName(name)

  clazz.getField("MODULE$").get(clazz).asInstanceOf[T]
}  

scala> singleton[List.type].make(3, "a")                       
res0: List[java.lang.String] = List(a, a, a)
extempore
Very nice! Still a little wonky for my tastes but I may use this...
Dave