12

I need only one instance of a class, so I have to use an object instead of a class. I also need to set some initial value chosen by a client, so I need to a constructor for an object, something like this:

object Object1(val initValue: Int){
  //.....
}

I can't use this exact code in Scala. How do I deal with that then?

6
  • It doesn't follow that you have to use an object because you only need one instance. Is it a requirement that only one instance exists? Commented Jun 3, 2013 at 17:11
  • @DanielC.Sobral, it is. Commented Jun 3, 2013 at 17:24
  • How do you make sure that you create it before you access it? Commented Jun 3, 2013 at 21:53
  • @ziggystar, why do I have to make sure about it? Commented Jun 4, 2013 at 1:18
  • Well, what happens if you access it before you create it? Commented Jun 4, 2013 at 7:33

3 Answers 3

19

You have a couple of choices:

  1. Make it a class, have the client construct it, give the value in the parameter
    Pro: Preserves immutability
    Con: Having only a single instance might be hard to manage

  2. Add a variable for the param to the object, add a setter.
    Pro: You still have a singleton
    Con: There is mutable state now

  3. Implement a multiton
    Pro: Gives you (apparent) immutability and singleton (per param)
    Con: More code to implement

You could implement a multiton like this in scala:

class Object1 private (val initValue: Int) {
  // ...
}

object Object1 {
  val insts = mutable.Map.empty[Int, Object1]

  def apply(initV: Int) =
    insts.getOrElseUpdate(initV, new Object1(initV))
}

UPDATE You could also turn this into a "singleton with parameter":

object Object1 {
  var inst: Option[(Int, Object1)] = None

  def apply(initV: Int) = inst match {
    case Some((`initV`, i)) => i
    case Some(_) =>
      sys.error("Object1 already instantiated with different param")
    case None =>
      val i = new Object1(initV)
      inst = Some((initV, i))
      i
  }
}
Sign up to request clarification or add additional context in comments.

4 Comments

the apply() in your "singleton with parameter" is not thread-safe.
Ah, yes, indeed (neither is the "multiton" by the way). I guess there is no one-fits-it all solution for making these thread safe. Most efficient would be to create and then to CAS, but that might initialize multiple times.
Solution 1 looks as good as using var insts, and initializing it later because anyways mutable kind of stuff is in use.
In my case, the apply method needs to return this.
5

The object isn't created until you reference it, so you could do something like the following:

object Test1 extends App {
  var x = Console.readLine
  println(Object1.initVal)
}

object Object1 {
  val initVal:String = Test1.x
}

1 Comment

Why this is not generic is because many times the other entity(Test1 here) won't be an object necessarily.
0

This is rather convention over configuration approach. But it is thread safe and adds obligatory initialisation requirement though a bit verbose:

    abstract class NetworkPusher() {
      private var networkAddress: String = ""
      def setNetworkAddr(addr: String) = networkAddress = addr
      def getNetworkAddr() = networkAddress
    }

    object NetworkPusherFactory {
    
      private var initOnceReady: NetworkPusher => Unit = _
    
      private lazy val initializedInstance = {
        val pusher =  new NetworkPusher(){}
        initOnceReady(pusher)
        pusher
      }
      def create(init: NetworkPusher => Unit): NetworkPusher = {
        initOnceReady = init
        initializedInstance
      }
    }
    
    object Main {
      def main(args: Array[String]): Unit = {
        val networkAddr = "A.D.D.R" // args[0]
        val onePusher = NetworkPusherFactory.create(
          instance => instance.setNetworkAddr(networkAddr)
        )
        println(s"using ${onePusher.getNetworkAddr}")
      }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.