Scala Language Classes and Objects Singleton & Companion Objects


Example

Singleton Objects

Scala supports static members, but not in the same manner as Java. Scala provides an alternative to this called Singleton Objects. Singleton objects are similar to a normal class, except they can not be instantiated using the new keyword. Below is a sample singleton class:

object Factorial {
    private val cache = Map[Int, Int]()
    def getCache = cache
}

Note that we have used object keyword to define singleton object (instead of 'class' or 'trait'). Since singleton objects can not be instantiated they can not have parameters. Accessing a singleton object looks like this:

Factorial.getCache() //returns the cache

Note that this looks exactly like accessing a static method in a Java class.

Companion Objects

In Scala singleton objects may share the name of a corresponding class. In such a scenario the singleton object is referred to as a Companion Object. For instance, below the class Factorial is defined, and a companion object (also named Factorial) is defined below it. By convention companion objects are defined in the same file as their companion class.

class Factorial(num : Int) {

  def fact(num : Int) : Int = if (num <= 1) 1 else (num * fact(num - 1))

  def calculate() : Int = {
    if (!Factorial.cache.contains(num)) {    // num does not exists in cache
      val output = fact(num) // calculate factorial
      Factorial.cache += (num -> output)     // add new value in cache
    }

    Factorial.cache(num)
  }
}

object Factorial {
  private val cache = scala.collection.mutable.Map[Int, Int]()
}

val factfive = new Factorial(5)
factfive.calculate  // Calculates the factorial of 5 and stores it
factfive.calculate  // uses cache this time
val factfiveagain = new Factorial(5)
factfiveagain.calculate  // Also uses cache

In this example we are using a private cache to store factorial of a number to save calculation time for repeated numbers.

Here object Factorial is a companion object and class Factorial is its corresponding companion class. Companion objects and classes can access each other's private members. In the example above Factorial class is accessing the private cache member of it's companion object.

Note that a new instantiation of the class will still utilize the same companion object, so any modification to member variables of that object will carry over.