Scala Foundation Course - Objects & Apply Methods


Welcome back. We already learned about Scala classes. I hope you understand that the class is a blueprint that we use to instantiate one or multiple objects. However, there is a terminology conflict in Scala and other Object-Oriented languages. We often see two terms.

  1. Instance of a class
  2. Object

In the following example, small, medium, and large circles are objects. But we also call them as an Instance of a Circle class.

                                
    val smallCircle  = new Circle(5)
    val mediumCircle = new Circle(25)
    val largeCircle  = new Circle(100)                                          
                            

I mean, those two terms are synonymous in most of the object-oriented languages including Java and C++. But while speaking in Scala, I prefer to call them an Instance of a Class. I won't call them an object. Because, In Scala, an Object is a different thing.

What is Scala Object?

A Scala object is a special type of class that can have one and only one instance. If you are familiar with Java design patterns, you already know what it means. A Scala object represents a singleton class. And instead of calling them a class, we call them an Object.
Once you know that the Scala object is a special type of class, you might be wondering with the following questions.

  1. When do we use Scala Objects?
  2. How to create a Scala Object?

When to use Scala Objects?

The simplest use of Scala object is as a home for utility methods. I mean, you might want to create a set of related methods that you can call without even instantiating a class. How do you do that in Java? Static Methods. Right?
Scala doesn't support static members. So, if you are looking for a mechanism to define a static method in Scala, you must place them in an object. Let me give you an example.
Scala Console object is an excellent example of this use case. Scala console is an Object. And it is a home for many useful methods to deal with the console outputs. Here is an Example.

                                
    Console.println(s"${Console.RED}Ha Ha ${Console.RESET} He He..")                                             
                            

Static methods in Scala Objects

You might also want me to create a brand-new example to help you understand the syntax. Let's do it. Here is the code for a static date-time utility.

                                
    import java.util.Calendar
    import java.text.SimpleDateFormat
    object StaticDateTime {   
        private valdateFormat = "EEEE, d-MMM-yyyy"
        private valtimeFormat = "K:m aa z(ZZ)"
        def currentDate:String = getCurrentDateTime(dateFormat)
        def currentTime:String = getCurrentDateTime(timeFormat)  
        def dateAdd(date:String, days:Int):String = {
            val df = new SimpleDateFormat(dateFormat)
            val dt = df.parse(date)
            val cal = Calendar.getInstance()
            cal.setTime(dt)
            cal.add(Calendar.DATE, days)
            df.format(cal.getTime())    
        }    
        private def getCurrentDateTime(format: String): String = {
            val df = new SimpleDateFormat(format)
            val cal = Calendar.getInstance()
            df.format(cal.getTime())
        }
    }                                               
                            

If you look at the code carefully, it appears to be a class definition. The only difference is the object keyword instead of a class keyword. Rest of the code is same as a Class definition. We have two private properties. Then we have three public methods. We have one private method as well. But that is not a class. It's already an object. You don't need to instantiate it using a new keyword. You can directly use it. Just like a static member in your Java application.

                                
    //How to Use Scala Object Methods
    StaticDateTime.currentDate
    StaticDateTime.currentTime
    StaticDateTime.dateAdd(StaticDateTime.currentDate,5)                                        
                            

Limitations of Scala Object

The definition of the above Object looks like a class definition. However, it is an object, and there are few restrictions on an object.

  1. Objects can extend or inherit Classes, but the opposite is not allowed. You cannot extend an object to create a class or another object.
  2. Objects cannot have a public constructor. And that makes sense as well. Because they are singleton objects and you don't want to use them as a blueprint to instantiate new objects.
  3. Scala will instantiate the object on their first use. Next time onwards, It uses the same instance. If you are not using the object, Scala doesn't instantiate it.

You can see the last point in action.

                                
    object TestSingleton{
        println("First Use..")
        def sayHello = println("Hi there!")
    }  
    TestSingleton.sayHello
    //Now try it once again.
    TestSingleton.sayHello
    TestSingleton.sayHello                                      
                            

How to implement a Singleton pattern in Scala

We have seen one use of Scala Objects. We used the object as a collection of static methods. The next possible use of Scala object is for implementing a singleton design pattern. I hope you are already familiar with singleton pattern and it's use cases. People use a singleton object when they need one and only one instance of the class. Let's try to understand it with an example.
You have an application level configuration file. You keep some configuration settings in the file and use them to customize the application behaviour. As part of your design, you don't want your application to create multiple objects and load the configuration data again and again. Instead, you would prefer to keep one single object and reuse the same for every reference.
Singleton Object is a common alternative to implement it. In your production application, you might want to use some existing library. One popular option is the config library developed by the Lightbend team. However, for our learning, here is a basic form of the code.

                                
    //Create a configuration file in current directory
    //File Name - config.properties
    //Paste below content
    dbpassword=dont-tell-password
    database=localhost
    dbuser=prashant
                                    
    //Code Example
    import java.util._
    import java.io._
    object appConfig{
        private val prop = new Properties();
        prop.load(new FileInputStream("config.properties"));   
        def config = prop
    }
    //How to use it
    appConfig.config.getProperty("dbuser")
    appConfig.config.getProperty("database")                                        
                            

Let's look at some key things. Since appConfig is an object, no one can instantiate it. All you can do with this object is to use it. When you use it for the first time, it will instantiate a properties object and load the property file. Every time you call the config method, it simply returns the same instance. So, no matter how many times, and from where do you call this object, it won't reload and create multiple property objects.
Great. I think this example offers an excellent opportunity to explain one more related concept.

Scala Apply Method

Scala classes as well as Scala objects, both offer a default method that we name as the apply method. We sometimes call it an injector method. You can invoke this method without a name. Let me show you what I mean. Here is a modified version of the app config object.

                                
    object appConfig{
        private val prop = new Properties();
        prop.load(new FileInputStream("config.properties"));   
        def apply(s:String) = prop.getProperty(s)
    }
    //How to use it
    appConfig("dbuser")
    appConfig("database")                                       
                            

I added a public method apply to the above object. The method takes the property key and returns the property value. It is as simple as a normal public method. You can call this method like below.

                                
    appConfig.apply("dbuser")                                       
                            

However, since I named this method as apply. A magic happens. I can call this method without the name. Like below.

                                
    appConfig("dbuser")                                       
                            

I am not saying appConfig.apply, I simply use a pair of parenthesis and pass the argument, right after the object name, and it works.
The apply method is the default method of an object. If you don't specify a method name, and simply pass the arguments in a pair of parenthesis, Scala calls the apply method. The apply method is not specific to objects. You can define the apply method in a Class also. Scala library is full of Apply methods. Have you used Scala lists? Let me show you. In the below example, I have a simple list of strings.

                                
    valmyList = List("India", "America", "Japan", "China")
    myList(0)
    myList(2)                                       
                            

If I use my myList(0)>, it gives me the string at the zeroth index. If I say myList(2)>, It gives me the string at the second position. What am I doing? I am calling the apply method. See below.

                                
    myList.apply(2)                                       
                            

The former syntax looks nice compared to the later one. Isn't it. Great.
That's it for this session. We will continue our discussion on Scala Objects in the next session.
Thank you for watching learning journal. Keep learning and keep growing.


You will also like:


Kafka Core Concepts

Learn Apache Kafka core concepts and build a solid foundation on Apache Kafka.

Learning Journal

Apache Spark Introduction

What is Apache Spark and how it works? Learn Spark Architecture.

Learning Journal

Pattern Matching

Scala takes the credit to bring pattern matching to the center.

Learning Journal

Pure Function benefits

Pure Functions are used heavily in functional programming. Learn Why?

Learning Journal

Immutability in FP

The literal meaning of Immutability is unable to change? How to program?

Learning Journal