Scala Foundation Course - Class Constructors


Welcome back. We already learned some basics of a Scala class definition. Now it's time to look at the constructors.
In this lesson, I will talk about following items.

  1. Default Constructor
  2. Primary Constructor
  3. Auxiliary Constructor

Default Constructor

Let's start with the default constructor.
Every Scala class comes with a default primary contractor that doesn't take any argument.


    class Circle { 
        var radius = 0
    }    

So, if you look at the above example, you don't see a code for a constructor. We haven't defined any constructor. But there is a default constructor that doesn't take any argument. And that's why we can instantiate this class using an empty argument list.


    val c = new Circle()   

If you want to change the default constructor, you have two options. Primary constructor and an auxiliary constructor. Let's talk about the primary constructor.

Primary Constructor

I want to take you back to the Java world and build Scala concept on top of that. So, let's look at a typical Java class.

                                
    public class Circle{
        //Instance variable
        private int radius; 
                                
        //Constructor
        public Circle(intnewRadius) {
            this.radius = newRadius;
        }
                                
        //Get and Set methods
        public intgetRadius() {
            return this.radius;
        }
        public void setRadius(int r) {
            this.radius = r;
        }
    }                                                   
                            

In the above code, we have a public class. We declare some private variables. Create a constructor. Then we create a get and a set method. Right?
Scala's philosophy is to save you from unnecessary typing and help you create a concise code. On that note, we already learned that if we make the radius public, we can get rid of those two get/set methods. Scala compiler will automatically generate those methods. We already learned that. Right? We also learned that there is no need to type the public modifier for the class. If we remove all those things, we are left with below lines.

                                
    class Circle {
        //Instance variable
        int radius; 
                                    
        //Constructor
        Circle(intnewRadius) {
            this.radius = newRadius;
        }
    }                                               
                            

Scala creators said, why the hell you want to type the class name and curly braces once again for defining a constructor? We already typed the class name for the class definition, so pass the arguments right there. We already have a pair of curly braces for the class, so use that as the body of your constructor. Amazing. Isn't it? If we make those changes, we have a Scala class with a primary constructor.

                                
    class Circle(var newRadius:Int) { 
        var radius = newRadius
    }                                               
                            

The Circle is your class name and the constructor as well. If you don't pass any arguments, Scala will give you a constructor with no arguments. We call that a default constructor. If you pass some arguments, Scala will give you a constructor with those arguments. We call that one a primary constructor.
The part, inside the pair of curly braces is the class body as well as a constructor body. And hence, Scala executes all statements in the class definition.
But that is not enough. Scala doesn't stop there. It goes one step further to help you create a concise code. Let me show you that as well.
Instantiate the above class and check the list of methods. Do you notice something unusual? We have a reader and a write for the radius. I expected that because I declared a public var. But why the hell we have a reader and a writer method for the newRadius. It looks like Scala took the newRadius and made it a public var. And that's why we see a reader and a writer for the newRadius.
What does that mean? That means, there was no need to declare the radius and initialize it with the constructor parameter. I should have declared my class like this.

                                
    class Circle(var radius:Int)                                          
                            

That's it. And Scala takes care of declaring a variable for radius, initialize it with the constructor parameter and also create a reader and a writer method. So, the one line of Scala code is equal to those several lines of Java code. Amazing. Isn't it?

How a var and val are different in Scala Constructor

Let me ask you few questions. We used a var type argument for the primary constructor. What happens if we change it to val?

                                
    class Circle(val radius:Int)                                          
                            

We learned this in the earlier lesson. The val is a read-only type. So, Scala won't create a writer method. Next question. What if I don't even want a reader? How to do that?
Remember? I asked that question in the earlier lesson. The answer is still same. Make it a private val . Scala will create the reader, but it will make that reader private.

                                
    class Circle(private val radius:Int)                                         
                            

There is another alternative to achieve the same. Don't tell Scala about the type.

                                
    class Circle(radius:Int)                                          
                            

Above code doesn't specify anything. Neither a val nor a var. As a result, Scala won't create a reader or a writer. It is as good a private val. However, in this case, Scala makes the radius an object-private field. I hope you understand the difference between a private and an object-private field.


Auxiliary Constructor

So far so good. But when I create a primary constructor, I lose the default constructor. The constructor with no arguments is the default constructor. If you define some arguments, it becomes the primary constructor, and you lose the constructor that takes no arguments. How do you fix that?
In some cases, you might need multiple constructors. Let's try to understand that with the help of an example.
I have a requirement to create a class for a Box. The Box should have three instance variables.

  1. Width
  2. Height
  3. Depth

We also need three different constructors.

  1. A default constructor that doesn't take any argument. The default constructor should set all those the variables to a unit value.
  2. We also need a proper constructor that takes all three arguments.
  3. For the sake of demonstration, we need a third constructor that takes only width and height. This constructor should set the depth as a unit value.

Along with these three constructors, we also need reader and writer methods for all three variables. How can we do that in Scala style?
Let me explain. We need three constructors.

  1. No argument constructor
  2. Two argument constructor
  3. All three argument constructor.

The method is simple. Define one of those as a primary constructor, and other two goes as an auxiliary constructor. But which one do you want to define as a primary constructor?
There is a simple rule of thumb. Make all argument constructor as a primary and define others as an auxiliary constructor. Why is that rule? I will explain that in a minute. But before that, let's look at the code.

                                
    class Box(varwidth:Int, varheight:Int, vardepth:Int){
        //Auxiliary constructors
        def this()= {
            this(1,1,1);
        }
        def this(w:Int, h:Int){
            this(w,h,1);
        }
        def showBox = println(s"width = $width height= $height depth=$depth")
    }                                           
                            

The first line defines the class and the primary constructor. The primary constructor takes width, height and the depth of the box. That first line does a lot of things for us.

  1. It defines the class.
  2. It also defines three instance variables. Width, Height, and the Depth.
  3. It goes further and defines the reader and writer for all three variables.
  4. That same line also defines the three-argument constructor.

That's why we always make the all-argument constructor as primary. If you make the no-argument constructor as primary, you won't get item 2 and 3 from above list. Rest of the code is simple.
We also define two auxiliary contractors. The auxiliary constructor name is always this. So, both are named as this. The first constructor takes no arguments and the second constructor takes two arguments. There is one more rule for the auxiliary constructor. The auxiliary constructor must start with a call to a previously defined auxiliary constructor or the primary constructor. In our example, both auxiliary constructors are calling the primary constructor. The first one is setting all values to 1 whereas the second one is setting the depth as 1.
The last line is to display all the three values. I kept it there for testing my code. Now you can instantiate the Box class with no arguments, two arguments or three arguments.

                                
    val b = new Box()
    b.showBox
    val b = new Box(5,3)
    b.showBox
    val b = new Box(5,3,2)
    b.showBox                                           
                            

Great. That's all about Scala constructors. In the next session, I will talk about some other Scala Object Oriented concepts.
Keep Learning and Keep growing.


You will also like:


Pattern Matching

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

Learning Journal

Anonymous Functions

Learn Scala Anonymous Functions with suitable examples.

Learning Journal

Referential Transparency

Referential Transparency is an easy method to verify the purity of a function.

Learning Journal

Statements and Expressions

Statements and Expressions in Scala. How are they different?

Learning Journal

Lazy Evaluations

Evaluate the expression now vs evaluate it for the first use. Strict vs Lazy?

Learning Journal