0

I have a bunch of singleton "worker" objects, and a central "repository" that is a thinly disguised map, mapping worker names to workers:

trait Worker { def work(): String }
object WorkerA extends Worker { [...] }
[...]
object WorkerX extends Worker  { [...] }
object Repository {
  private val repo: scala.collection.mutable.Map[String,Worker] = Map()
  def register(name:String,worker:Worker) = repo.put(name,worker)
}

I would really like the Repository to be automatically populated with all the workers at start of the program, so I tried something like this:

object WorkerA extends Worker {
  ... 
  println("Registering A")
  Repository.register("A",this)
}

but to my surprise "Registering A" was never printed (and the worker was not registered at the repository). I found out that this is because Scala is lazy about initializing companion objects.

So, is there a way to force non-lazy initialization, or any other way that I can do what I want in Scala (short of using reflection or keeping an explicit list of workers in the definition of Repository)?

holbech
  • 573
  • 3
  • 8
  • Check this [DelayedInit approach](http://stackoverflow.com/questions/6249569/force-initialization-of-scala-singleton-object) – John K Jun 01 '16 at 14:13
  • 1
    You can define them as `val WorkerA = new Worker { ... }` so that they will be initialized eagerly. – ale64bit Jun 01 '16 at 15:30
  • There is no way to "force non-lazy initialization" for objects. The JVM would have to be "omniscient". Imagine you add another library/jar to your classpath containing more classes that inherit `Worker`, how would the system have the slightest knowledge of these and invoke their constructors? You would have to crawl the classpath and inspect all classes. I think @bali182 's answer is correct, you should pro-actively populate your map. Another option would be to have the repo provide an opaque key that the worker requires, that way at least you cannot invoke an unregistered worker. – 0__ Jun 01 '16 at 20:56
  • See also: https://stackoverflow.com/questions/492184/how-do-you-find-all-subclasses-of-a-given-class-in-java – 0__ Jun 01 '16 at 21:00

1 Answers1

2

I don't think registering themselves in a repository is the responsibility of the Worker constructor. If you have only objects, I'd do this (clearer for the reader too):

object Repository {
  val workers: Map[String, Worker] = Map(
    "a" -> WorkerA, // or whatever their names are
    "x" -> WorkerX
  )
}

If you want to do it dynamically too, then I'd hide the underlying map, like you did originally - since it has to be mutable - and do the registering after creation. Also I'd make the registering the responsibility of the creator.

Balázs Édes
  • 13,452
  • 6
  • 54
  • 89