Companion Object in Scala

Reading Time: 4 minutes

In order to understand the use of companion objects, it is important to understand the static members first. We have learned that in object-oriented languages, classes are the blueprint that contains members such as fields and methods. But in order to access these fields or methods, we first need to construct the objects from these classes.

Let’s look at an example.

class Math 
{
    private val max = 100
    def sum(a: Int, b: Int): Int = a + b
}

object Test {
    def main(args: Array[String]): Unit = {
        val math = new Math()
        math.sum(5, 10)
    }
}

We created a class called Math with a method called sum, which takes in two numbers and returns the sum as the result.

In order to execute this code, we create an instance of this Math class and invoked the sum method bypassing 5 and 10, receiving 15 as the output. However, as we see, the sum method is not dependent on any of the member variables of the Math class.

For example, the max member variable in this case. So, there should be no need to create an instance of Math class in order to invoke the sum method. We should be able to call this directly in this case. And this is where the companion objects come into the picture.

There are four things that we have to remember about companion objects:

1. They share the same name as the corresponding class.

2. They start with the “object” keyword.

3. They live in the same source file as the corresponding classes.

4. The companion objects and the corresponding classes acts as each other’s private members.

The “object” keyword tells that this is a singleton object. In other words, it means that while your program is running, you may create as many instances from your classes as you want, but the singleton object would be just one, and there will not be multiple instances of it.

Let’s see them in action using our Math example.

object Math {
    def sum(a: Int, b: Int): Int = a + b
    def getPrivateMember: Int = = new Math().max
}

class Math {
    private val max = 100
}

object Test {
    def main(args: Array[String]): Unit = {
        Math.sum(5, 10)
        Math.getPrivateMember
    }
}

As we see, we have created a new singleton object called Math, which has the same name as our class Math. It also starts with the “object” keyword and remains in the same file as the class Math.

We moved the implementation for the sum from the class to it’s companion object. This is because, as we know that the sum implementation is not dependent on the member variables for the Math class, putting that implementation into the companion object will help the callers to not create the instance of Math class and call it directly.

There is another method we have written to show that the companion object has access to the private members of its class.

Here the getPrivateMember instantiates the Math class and returns it private member named “max”. There is one additional thing to note here. When we define the getPrivateMember, we did not put the parentheses. In Scala, there is a convention in which if the method has no arguments to take and does not perform any side effect, meaning that it’s a pure function, we may choose to omit the parentheses.

Here, getPrivateMember is just returning the value of the member variable, so we choose to omit the parentheses.

Math.sum(5, 10)
Math.getPrivateMember

When we execute the sum method, we executed it from the Math companion object and did not have to create the new instance of Math class. Additionally, we were able to access the private member variable of the Math class from the companion object.

Creating Objects Using Apply

We know that in order to create a new instance of an object, we need to use the “new” keyword.

For example:

class Person(firstName: String, lastName: String) {
	def getName: String = firstName + lastName
}

object Test {
    def main(args: Array[String]): Unit = {
        val alice = new Person("Alice", "Christy")
    }
}

We have a class called “Person” with the firstName and lastName as class parameters. And we create a new instance of Person as shown above. We created “alice” as a new Person, passing in the first name and the last name.

However, in Scala, there is one more way to create objects without using the new keyword.

There is a method called “apply” in companion object that is treated specially by the Scala compiler, and it lets us create new instances of classes without requiring the new keyword. Let’s learn how to use it in our code.

object Person {
  def apply(firstName: String, lastName: String): Person = new Person(firstName, lastName)
}

class Person(firstName: String, lastName: String) {
  def getName: String = firstName + " " + lastName
}

object Test {
  def main(args: Array[String]): Unit = {
    val alice = Person("Alice", "Christy")
    println(p.getName)
  }
}

As we see here, we’ve created a companion object with apply method into it. It takes the arguments that we need to create an instance of class Person, it creates the instance of Person internally, and returns the instance. As we see, we have created the instance of Person class without using the new keyword. And we can access the members just like any other object. 🙂

That’s all about Companion Object from this blog. Keep Learning, Keep Growing!!!

 

 

Knoldus-blog-footer-image

Written by 

Sarfaraz Hussain is a Big Data fan working as a Software Consultant with an experience of 1+ years. He is working in technologies like Spark, Scala, Java, Hive & Sqoop and has completed his Master of Engineering with specialization in Big Data & Analytics. He loves to teach and is a huge fitness freak and loves to hit the gym when he's not coding.