0

I am looking for a way to initialize a companion object with arguments. I tried this, it has the risk for re-instantiation.

private[mypackage] class A(in:Int) {
  def method = {}
}

object A {

  var singleton: Option[A] = None

  def getInstance(): A = {
    if(singleton.isDefined)
      singleton.get
    else {
        throw InitializationException("Object not configured")
      }
  }

  def getInstance(in:Int): A = {
    singleton = Some(new A(in))
    singleton.get
  }
}

Is there a better way?

Mohitt
  • 2,957
  • 3
  • 29
  • 52
  • if you need a singleton object say `Cat` you can declare `object Cat` compiler ensures single instance of `Cat` is available in that JVM instance. note that Type of `Cat` object will be `Cat.type` – Nagarjuna Pamu Aug 27 '16 at 10:45

2 Answers2

1

Pure Scala way

Scala allows you to create a singleton object of a type using object keyword. Scala ensures only one instance of A is available in the system.

private[myPackage] object A  {
  val configValue = Config.getInt("some_value")
  def fn: Unit = ()
}

type of A object

scala> object A {}
defined object A

scala> :type A
A.type

more about singleton objects in scala Explanation of singleton objects in Scala

Guice Annotations

import com.google.inject.Singleton

@Singleton
class A (val value: Int) {
  def fn: Unit = ()
}

Classic Java way

Use synchronized keyword to protect the getInstance from creating more than one object when called. of course constructor of the class has to be private

Community
  • 1
  • 1
Nagarjuna Pamu
  • 14,737
  • 3
  • 22
  • 40
1

You can use a lazy val to delay creation of your singleton, and base it on a var that should be updated once during start-up sequence:

object A {
  // will be instantiated once, on first call
  lazy val singleton: A = create()

  private var input: Option[Int] = None

  // call this before first access to 'singleton':
  def set(i: Int): Unit = { input = Some(i) }

  private def create(): A = {
    input.map(i => new A(i))
      .getOrElse(throw new IllegalStateException("cannot access A before input is set"))
  }
}
Tzach Zohar
  • 37,442
  • 3
  • 79
  • 85
  • `lazy val` is thread-safe (and rather slow) only for 2.11.* scala. Future scala versions and dotty will use different algorithm, so one would need to add `@volatile` to save thread-safety. See http://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html for details. – dveim Aug 27 '16 at 12:36
  • See https://d-d.me/talks/scalar2016/#/39 , "both thread-safe and thread-unsafe lazy vals.". IIRC to achieve thread-safety one would need to add @volatile. – dveim Aug 27 '16 at 13:03