Companion Object

    In Scala, when you have defined a class with the same name as a singleton object, it is called a companion class, and the singleton object will be called a companion object. The companion object and companion class should be defined in a single file. Companion objects can access the private members and functions of the companion class.

    Syntax:

    class CompanionDemo {
    
    }
     
    object CompanionDemo {
    
    }

    Scala Companion Example

    The above image has some symbols on the left of the class and object, which denotes that the class has one companion object declared and the object has a companion class.

    Example:

    CompanionDemo.scala

    class CompanionDemo {
    
     // Variables of Companion class
     var str1 = "TGB Learner"
     var str2 = "Time to learn Companion Object"
    
     // Method of Companion class
     def show():String = {
       str1 + "\n" + str2
     }
    }
     
    object CompanionDemo {
    
     def apply() = {
       println("This is companion object")
     }
    
     def greet(): String = {
       println("This is companion object")
       val companionObject = new CompanionDemo
       companionObject.show()
     }
    }
    CompanionExample.scala
    object CompanionExample extends App {
       print(CompanionDemo.greet())
    }

    Output:

    This is companion object
    
    TGB Learner
    
    Time to learn Companion Object

    Advantages of Companion Objects

    1. Companion object and companion class can access private and public members of each other.

    For example: If I update the above example a little bit, it will still produce the same output:

    CompanionDemo.scala

    class CompanionDemo {
    
     // Variables of Companion class
     var str2 = "Time to learn Companion Object"
    
     // Method of Companion class
     def show():String = {
       CompanionDemo.str1 + "\n" + str2 //It is able to access the variable str1
     }
    }
    
    object CompanionDemo {
    
     var str1 = "TGB Learner"       // str1 defined in companion object now
    
     def apply() = {
       println("This is companion object")
     }
     
     def greet(): String = {
       println("This is companion object")
       val companionObject = new CompanionDemo
       companionObject.show()
     }
    }

    2. Companion object allow you to use the object without the need for the new keyword. For this reason, we can use most of the collections without specifying a new keyword.

    For Example:

    val listOfString = List("No", "new", "keyword", "required")
    
    // Hence list is also a companion object.
    
    
    Note: You can use Ctrl+Click on intellij idea IDE to view the definition of how List is created as a companion object

    Defining an apply method in a companion object has a special meaning to the Scala compiler. There’s a little syntactic sugar baked into Scala that lets you type this code:

    val listExample = List(100, 200)

    During the compilation process, the compiler turns that code into the below code:

    val p = List.apply(100, 200)

    The apply method in the companion object acts as a Factory Method . Scala’s syntactic sugar lets you use the syntax shown, creating new class instances without using the new keyword.

    Another Example to demonstrate the above :

    User.scala

    class User {
     var name: Option[String] = None
     var age: Option[Int] = None
     override def toString = s"$name, $age"
    }
    
    object User {
     def apply(name: Option[String]): User = {
       var p = new User
       p.name = name
       p
     }
    
     def apply(name: Option[String], age: Option[Int]): User = {
       val user = new User
       user.name = name
       user.age = age
       user
     }
    }

    UserExample.scala

    object UserExample extends App {
    
     val user1 = User(None)
     val user2 = User(Some("TGB User"))
     val user3 = User(Some("Meet"), Some(26))
    
     println(user1)
     println(user2)
     println(user3)
    }